diff --git a/CMakeLists.txt b/CMakeLists.txt index a00dcaed0..31ef6f003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "STKRelease") endif() +option(SERVER_ONLY "Create a server only (i.e. no graphics or sound)" OFF) option(USE_FRIBIDI "Support for right-to-left languages" ON) option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON) option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF) @@ -34,7 +35,7 @@ else() set(WIIUSE_BUILD ON) endif() -if(MINGW OR CYGWIN) +if(MINGW OR CYGWIN OR SERVER_ONLY) option(USE_WIIUSE "Support for wiimote input devices" OFF) else() option(USE_WIIUSE "Support for wiimote input devices" ON) @@ -68,6 +69,11 @@ if(USE_GLES2) add_definitions(-DUSE_GLES2) endif() +if(SERVER_ONLY) + add_definitions(-DSERVER_ONLY) + add_definitions(-DNO_IRR_COMPILE_WITH_X11_) +endif() + # Build the Bullet physics library add_subdirectory("${PROJECT_SOURCE_DIR}/lib/bullet") include_directories("${PROJECT_SOURCE_DIR}/lib/bullet/src") @@ -77,7 +83,7 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/lib/enet") include_directories("${PROJECT_SOURCE_DIR}/lib/enet/include") # Build glew library -if(NOT USE_GLES2) +if(NOT USE_GLES2 AND NOT SERVER_ONLY) add_definitions(-DGLEW_NO_GLU) add_subdirectory("${PROJECT_SOURCE_DIR}/lib/glew") include_directories("${PROJECT_SOURCE_DIR}/lib/glew/include") @@ -206,12 +212,13 @@ if (OPENMP_FOUND) endif() # OpenGL -if(NOT USE_GLES2) +if(NOT USE_GLES2 AND NOT SERVER_ONLY) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR}) endif() -if(UNIX AND NOT APPLE) + +if(UNIX AND NOT APPLE AND NOT SERVER_ONLY) find_package(X11 REQUIRED) include_directories(${X11_INCLUDE_DIR}) @@ -370,10 +377,12 @@ target_link_libraries(supertuxkart ${FREETYPE_LIBRARIES} ) -if(NOT USE_GLES2) - target_link_libraries(supertuxkart ${OPENGL_LIBRARIES} glew) -else() - target_link_libraries(supertuxkart EGL GLESv2) +if(NOT SERVER_ONLY) + if(NOT USE_GLES2) + target_link_libraries(supertuxkart ${OPENGL_LIBRARIES} glew) + else() + target_link_libraries(supertuxkart EGL GLESv2) + endif() endif() if(UNIX AND NOT APPLE) diff --git a/data/shaders/grass_pass2.frag b/data/shaders/grass_pass2.frag index 76776c200..b5ebadbd9 100644 --- a/data/shaders/grass_pass2.frag +++ b/data/shaders/grass_pass2.frag @@ -54,6 +54,7 @@ void main(void) float scattering = mix(fPowEdotL, fLdotNBack, .5); float specmap = texture(SpecMap, uv).g; - vec3 LightFactor = color.xyz * (scattering * 0.1) + getLightFactor(color.xyz, vec3(1.), specmap, 0.); + float emitmap = texture(SpecMap, uv).b; + vec3 LightFactor = color.xyz * (scattering * 0.1) + getLightFactor(color.xyz, vec3(1.), specmap, emitmap); FragColor = vec4(LightFactor, 1.); } diff --git a/data/shaders/instanced_grass_pass2.frag b/data/shaders/instanced_grass_pass2.frag index bcce07ad3..4d69593f0 100644 --- a/data/shaders/instanced_grass_pass2.frag +++ b/data/shaders/instanced_grass_pass2.frag @@ -25,6 +25,7 @@ void main(void) #ifdef Use_Bindless_Texture vec4 color = texture(handle, uv); float specmap = texture(secondhandle, uv).g; + float emitmap = texture(secondhandle, uv).b; float mask = texture(thirdhandle, uv).a; #ifdef SRGBBindlessFix color.xyz = pow(color.xyz, vec3(2.2)); @@ -32,6 +33,7 @@ void main(void) #else vec4 color = texture(Albedo, uv); float specmap = texture(SpecMap, uv).g; + float emitmap = texture(SpecMap, uv).b; float mask = texture(colorization_mask, uv).a; #endif if (color.a < 0.5) discard; @@ -59,7 +61,8 @@ void main(void) float fLdotNBack = max(0., - dot(nor, L) * 0.6 + 0.4); float scattering = mix(fPowEdotL, fLdotNBack, .5); + + vec3 LightFactor = color.xyz * (scattering * 0.1) + getLightFactor(color.xyz, vec3(1.), specmap, emitmap); - vec3 LightFactor = color.xyz * (scattering * 0.1) + getLightFactor(color.xyz, vec3(1.), specmap, 0.); FragColor = vec4(LightFactor, 1.); } diff --git a/lib/glew/CMakeLists.txt b/lib/glew/CMakeLists.txt index 987e3e5b8..ca15ca01c 100644 --- a/lib/glew/CMakeLists.txt +++ b/lib/glew/CMakeLists.txt @@ -1,5 +1,6 @@ # CMakeLists.txt - glew +if (NOT SERVER_ONLY) include_directories("include") if(APPLE) @@ -18,3 +19,5 @@ add_library(glew STATIC ) target_link_libraries(glew ${OPENGL_LIBRARIES}) + +endif() diff --git a/lib/irrlicht/CMakeLists.txt b/lib/irrlicht/CMakeLists.txt index 1f8397131..debd4b8e6 100644 --- a/lib/irrlicht/CMakeLists.txt +++ b/lib/irrlicht/CMakeLists.txt @@ -8,9 +8,14 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/" "${ZLIB_INCLUDE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../zlib/") # For zconf.h on WIN32 -if(NOT USE_GLES2) - find_package(OpenGL REQUIRED) - include_directories(${OPENGL_INCLUDE_DIR}) +if (SERVER_ONLY) + add_definitions(-DNO_IRR_COMPILE_WITH_OPENGL_) + add_definitions(-DNO_IRR_COMPILE_WITH_X11_) +else() + if(NOT USE_GLES2) + find_package(OpenGL REQUIRED) + include_directories(${OPENGL_INCLUDE_DIR}) + endif() endif() if (UNIX AND NOT APPLE) diff --git a/lib/irrlicht/include/IrrCompileConfig.h b/lib/irrlicht/include/IrrCompileConfig.h index f091eccaf..0f3ee6e3e 100644 --- a/lib/irrlicht/include/IrrCompileConfig.h +++ b/lib/irrlicht/include/IrrCompileConfig.h @@ -246,6 +246,10 @@ define out. */ #ifdef NO_IRR_LINUX_XCURSOR_ #undef _IRR_LINUX_XCURSOR_ #endif +#else + +#undef _IRR_LINUX_X11_VIDMODE_ +#undef _IRR_LINUX_X11_RANDR_ #endif diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp index e2194d68d..951230dcd 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp @@ -68,12 +68,14 @@ namespace irr } } // end namespace irr +#if defined(_IRR_COMPILE_WITH_X11_) namespace { Atom X_ATOM_CLIPBOARD; Atom X_ATOM_TARGETS; Atom X_ATOM_UTF8_STRING; }; +#endif namespace irr { @@ -598,6 +600,7 @@ static GLXContext getMeAGLContext(Display *display, GLXFBConfig glxFBConfig, boo Context = glXCreateNewContext(display, glxFBConfig, GLX_RGBA_TYPE, NULL, True); return Context; } + #endif bool CIrrDeviceLinux::createWindow() diff --git a/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp b/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp index 58f98b85e..501152864 100644 --- a/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp +++ b/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp @@ -341,11 +341,25 @@ namespace video delete BridgeCalls; #if defined(EGL_VERSION_1_0) - // HACK : the following is commented because destroying the context crashes under Linux (Thibault 04-feb-10) - /*eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(EglDisplay, EglContext); - eglDestroySurface(EglDisplay, EglSurface);*/ - eglTerminate(EglDisplay); + eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (EglContext != EGL_NO_CONTEXT) + { + eglDestroyContext(EglDisplay, EglContext); + EglContext = EGL_NO_CONTEXT; + } + + if (EglSurface != EGL_NO_SURFACE) + { + eglDestroySurface(EglDisplay, EglSurface); + EglSurface = EGL_NO_SURFACE; + } + + if (EglDisplay != EGL_NO_DISPLAY) + { + eglTerminate(EglDisplay); + EglDisplay = EGL_NO_DISPLAY; + } #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) if (HDc) diff --git a/sources.cmake b/sources.cmake index ba4868d71..d4f28ae4d 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/config/hardware_stats.cpp b/src/config/hardware_stats.cpp index 91c07f56c..f657c6409 100644 --- a/src/config/hardware_stats.cpp +++ b/src/config/hardware_stats.cpp @@ -264,6 +264,9 @@ const std::string& getOSVersion() */ void reportHardwareStats() { +#ifdef SERVER_ONLY + return; +#else if(!UserConfigParams::m_hw_report_enable) return; @@ -335,8 +338,10 @@ void reportHardwareStats() if(nr_procs>0) json.add("cpu_numprocs", nr_procs); +#ifndef SERVER_ONLY json.add("GL_EXTENSIONS", getGLExtensions()); getGLLimits(&json); +#endif json.finish(); // ------------------------------------------------------------------------ @@ -391,7 +396,7 @@ void reportHardwareStats() request->setURL((std::string)UserConfigParams::m_server_hw_report+"/upload/v1/"); //request->setURL("http://127.0.0.1:8000/upload/v1/"); request->queue(); - +#endif // !SERVER_ONLY } // reportHardwareStats } // namespace HardwareStats diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index 08128fe5d..8e8d57d44 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -527,6 +527,7 @@ void FontWithFace::render(const core::stringw& text, FontSettings* font_settings, FontCharCollector* char_collector) { +#ifndef SERVER_ONLY const bool black_border = font_settings ? font_settings->useBlackBorder() : false; const bool rtl = font_settings ? font_settings->isRTL() : false; @@ -778,4 +779,5 @@ void FontWithFace::render(const core::stringw& text, } } } +#endif } // render diff --git a/src/graphics/2dutils.cpp b/src/graphics/2dutils.cpp index 38814a5b4..87bf3a16e 100644 --- a/src/graphics/2dutils.cpp +++ b/src/graphics/2dutils.cpp @@ -15,6 +15,7 @@ // 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 "graphics/2dutils.hpp" #include "graphics/central_settings.hpp" @@ -779,3 +780,6 @@ void GL32_draw2DRectangle(video::SColor color, const core::rect& position, glGetError(); } // GL32_draw2DRectangle + +#endif // !SERVER_ONLY + diff --git a/src/graphics/central_settings.cpp b/src/graphics/central_settings.cpp index a96ddf5ea..cea030f3f 100644 --- a/src/graphics/central_settings.cpp +++ b/src/graphics/central_settings.cpp @@ -15,6 +15,7 @@ // 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 "graphics/central_settings.hpp" #include "config/user_config.hpp" @@ -447,3 +448,4 @@ bool CentralVideoSettings::supportsHardwareSkinning() const { return isARBUniformBufferObjectUsable() && isARBExplicitAttribLocationUsable() && getGLSLVersion() >= 330; } +#endif // !SERVER_ONLY diff --git a/src/graphics/command_buffer.cpp b/src/graphics/command_buffer.cpp index 30745ac33..2e940deb8 100644 --- a/src/graphics/command_buffer.cpp +++ b/src/graphics/command_buffer.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 "graphics/command_buffer.hpp" #include "graphics/central_settings.hpp" #include "utils/cpp2011.hpp" @@ -275,4 +277,6 @@ void GlowCommandBuffer::fill(OtherMeshMap *mesh_map) glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); } //GlowCommandBuffer::fill -#endif // !defined(USE_GLES2) +#endif // !defined(USE_GLES2) + +#endif // !SERVER_ONLY \ No newline at end of file diff --git a/src/graphics/command_buffer.hpp b/src/graphics/command_buffer.hpp index c3d038ecb..6ae425c73 100644 --- a/src/graphics/command_buffer.hpp +++ b/src/graphics/command_buffer.hpp @@ -18,6 +18,8 @@ #ifndef HEADER_COMMAND_BUFFER_HPP #define HEADER_COMMAND_BUFFER_HPP +#ifndef SERVER_ONLY + #include "graphics/draw_tools.hpp" #include "graphics/gl_headers.hpp" #include "graphics/material.hpp" @@ -653,5 +655,6 @@ public: } } // multidraw }; -#endif // !defined(USE_GLES2) -#endif //HEADER_COMMAND_BUFFER_HPP +#endif // !defined(USE_GLES2) +#endif // !SERVER_ONLY +#endif // HEADER_COMMAND_BUFFER_HPP diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index af86018cf..b1ed2b2d1 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -15,7 +15,9 @@ // 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 "graphics/draw_calls.hpp" + #include "config/user_config.hpp" #include "graphics/draw_tools.hpp" #include "graphics/gpu_particles.hpp" @@ -899,3 +901,4 @@ int32_t DrawCalls::getSkinningOffset() const (const size_t previous, const STKAnimatedMesh* m) { return previous + m->getTotalJointSize(); }); } // getSkinningOffset +#endif // !SERVER_ONLY diff --git a/src/graphics/draw_calls.hpp b/src/graphics/draw_calls.hpp index 55d7b12c5..fc72c4cb9 100644 --- a/src/graphics/draw_calls.hpp +++ b/src/graphics/draw_calls.hpp @@ -18,6 +18,7 @@ #ifndef HEADER_DRAW_CALLS_HPP #define HEADER_DRAW_CALLS_HPP +#ifndef SERVER_ONLY #include "graphics/command_buffer.hpp" #include #include @@ -110,4 +111,5 @@ public: int32_t getSkinningOffset() const; }; +#endif // !SERVER_ONLY #endif //HEADER_DRAW_CALLS_HPP diff --git a/src/graphics/draw_policies.cpp b/src/graphics/draw_policies.cpp index c8ce67ef5..a37fe0295 100644 --- a/src/graphics/draw_policies.cpp +++ b/src/graphics/draw_policies.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 "graphics/draw_policies.hpp" #include "graphics/draw_tools.hpp" #include "graphics/materials.hpp" @@ -352,3 +354,5 @@ void MultidrawPolicy::drawReflectiveShadowMap(const DrawCalls& draw_calls, draw_calls.multidrawReflectiveShadowMaps(rsm_matrix); #endif //!defined(USE_GLES2) } + +#endif // !SERVER_ONLY \ No newline at end of file diff --git a/src/graphics/draw_policies.hpp b/src/graphics/draw_policies.hpp index d77bb9c22..ff362440f 100644 --- a/src/graphics/draw_policies.hpp +++ b/src/graphics/draw_policies.hpp @@ -18,6 +18,8 @@ #ifndef HEADER_DRAW_POLICIES_HPP #define HEADER_DRAW_POLICIES_HPP +#ifndef SERVER_ONLY + #include "graphics/draw_calls.hpp" @@ -91,5 +93,5 @@ public: const core::matrix4 &rsm_matrix ) const; }; - -#endif //HEADER_DRAW_POLICIES_HPP +#endif // !SERVER_ONLY +#endif // HEADER_DRAW_POLICIES_HPP diff --git a/src/graphics/explosion.cpp b/src/graphics/explosion.cpp index eba0951ac..4ce9b7493 100644 --- a/src/graphics/explosion.cpp +++ b/src/graphics/explosion.cpp @@ -41,9 +41,11 @@ Explosion::Explosion(const Vec3& coord, const char* explosion_sound, const char m_remaining_time = burst_time; m_emission_frames = 0; +#ifndef SERVER_ONLY ParticleKindManager* pkm = ParticleKindManager::get(); ParticleKind* particles = pkm->getParticles(particle_file); m_emitter = new ParticleEmitter(particles, coord, NULL); +#endif } // Explosion //----------------------------------------------------------------------------- @@ -51,10 +53,12 @@ Explosion::Explosion(const Vec3& coord, const char* explosion_sound, const char */ Explosion::~Explosion() { +#ifndef SERVER_ONLY if(m_emitter) { delete m_emitter; } +#endif } // ~Explosion //----------------------------------------------------------------------------- @@ -71,6 +75,7 @@ bool Explosion::updateAndDelete(float dt) m_emission_frames++; m_remaining_time -= dt; +#ifndef SERVER_ONLY if (m_remaining_time < 0.0f && m_remaining_time >= -explosion_time) { scene::ISceneNode* node = m_emitter->getNode(); @@ -88,7 +93,7 @@ bool Explosion::updateAndDelete(float dt) node->getMaterial(0).DiffuseColor.setRed(intensity); node->getMaterial(0).EmissiveColor.setRed(intensity); } - +#endif // Do nothing more if the animation is still playing if (m_remaining_time>0) return false; @@ -98,6 +103,7 @@ bool Explosion::updateAndDelete(float dt) // object is removed. if (m_remaining_time > -explosion_time) { +#ifndef SERVER_ONLY // if framerate is very low, emit for at least a few frames, in case // burst time is lower than the time of 1 frame if (m_emission_frames > 2) @@ -106,6 +112,7 @@ bool Explosion::updateAndDelete(float dt) m_emitter->getNode()->getEmitter()->setMinParticlesPerSecond(0); m_emitter->getNode()->getEmitter()->setMaxParticlesPerSecond(0); } +#endif } else { diff --git a/src/graphics/fixed_pipeline_renderer.cpp b/src/graphics/fixed_pipeline_renderer.cpp index 234fc3636..1910db80f 100644 --- a/src/graphics/fixed_pipeline_renderer.cpp +++ b/src/graphics/fixed_pipeline_renderer.cpp @@ -15,6 +15,7 @@ // 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 "graphics/fixed_pipeline_renderer.hpp" #include "config/user_config.hpp" #include "graphics/camera.hpp" @@ -112,3 +113,4 @@ std::unique_ptr FixedPipelineRenderer::createRenderTarget(const ir { return std::unique_ptr(new GL1RenderTarget(dimension, name)); } +#endif \ No newline at end of file diff --git a/src/graphics/fixed_pipeline_renderer.hpp b/src/graphics/fixed_pipeline_renderer.hpp index 96fb6ed76..9162d8b64 100644 --- a/src/graphics/fixed_pipeline_renderer.hpp +++ b/src/graphics/fixed_pipeline_renderer.hpp @@ -18,6 +18,7 @@ #ifndef HEADER_FIXED_PIPELINE_RENDERER_HPP #define HEADER_FIXED_PIPELINE_RENDERER_HPP +#ifndef SERVER_ONLY #include "graphics/abstract_renderer.hpp" #include @@ -37,4 +38,5 @@ public: const std::string &name); }; +#endif // !SERVER_ONLY #endif //HEADER_FIXED_PIPELINE_RENDERER_HPP diff --git a/src/graphics/geometry_passes.cpp b/src/graphics/geometry_passes.cpp index 268c88780..f9fb65400 100644 --- a/src/graphics/geometry_passes.cpp +++ b/src/graphics/geometry_passes.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 "graphics/geometry_passes.hpp" #include "graphics/callbacks.hpp" #include "graphics/draw_tools.hpp" @@ -380,5 +382,4 @@ void AbstractGeometryPasses::renderTransparent(const DrawCalls& draw_calls, } // renderTransparent - - +#endif // !SERVER_ONLY \ No newline at end of file diff --git a/src/graphics/geometry_passes.hpp b/src/graphics/geometry_passes.hpp index 70d450a4c..fc82b35bf 100644 --- a/src/graphics/geometry_passes.hpp +++ b/src/graphics/geometry_passes.hpp @@ -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 + #ifndef HEADER_GEOMETRY_PASSES_HPP #define HEADER_GEOMETRY_PASSES_HPP @@ -171,4 +173,5 @@ public: }; -#endif //HEADER_GEOMETRY_PASSES_HPP +#endif // !SERVER_ONLY +#endif // HEADER_GEOMETRY_PASSES_HPP diff --git a/src/graphics/gl_headers.hpp b/src/graphics/gl_headers.hpp index e02e59fd4..ee27b0f44 100644 --- a/src/graphics/gl_headers.hpp +++ b/src/graphics/gl_headers.hpp @@ -18,6 +18,8 @@ #ifndef GL_HEADER_HPP #define GL_HEADER_HPP +#ifndef SERVER_ONLY + #define GLEW_STATIC extern "C" { @@ -80,5 +82,12 @@ struct DrawElementsIndirectCommand{ GLuint baseVertex; GLuint baseInstance; }; +#else + typedef unsigned int GLuint; + typedef unsigned int GLsync; + typedef unsigned int GLenum; + +#endif // server only #endif + diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp index b411c604d..295f27fb8 100644 --- a/src/graphics/glwrap.cpp +++ b/src/graphics/glwrap.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 "graphics/glwrap.hpp" #include "config/hardware_stats.hpp" @@ -758,3 +760,6 @@ else \ #endif // ifdef XX } // getGLLimits + +#endif // !SERVER_ONLY + diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp index 791a5ed8d..d59393448 100644 --- a/src/graphics/glwrap.hpp +++ b/src/graphics/glwrap.hpp @@ -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 + #ifndef GLWRAP_HEADER_H #define GLWRAP_HEADER_H @@ -168,3 +170,6 @@ const std::string getGLExtensions(); void getGLLimits(HardwareStats::Json *json); #endif + +#endif // supertuxkart + diff --git a/src/graphics/gpu_particles.cpp b/src/graphics/gpu_particles.cpp index 0406c90f5..261ee565b 100644 --- a/src/graphics/gpu_particles.cpp +++ b/src/graphics/gpu_particles.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 "graphics/gpu_particles.hpp" #include "config/user_config.hpp" @@ -633,3 +635,5 @@ void ParticleSystemProxy::render() { draw(); } } + +#endif // SERVER_ONLY diff --git a/src/graphics/gpu_particles.hpp b/src/graphics/gpu_particles.hpp index d23d3952f..0b52244e3 100644 --- a/src/graphics/gpu_particles.hpp +++ b/src/graphics/gpu_particles.hpp @@ -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 + #ifndef HEADER_GPU_PARTICLES_HPP #define HEADER_GPU_PARTICLES_HPP @@ -109,3 +111,5 @@ public: }; #endif // GPUPARTICLES_H + +#endif // !SERVER_ONLY diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index de8f93099..99e152b2b 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -70,11 +70,13 @@ * Should help prevent distros building against an incompatible library. */ -#if (IRRLICHT_VERSION_MAJOR < 1 || IRRLICHT_VERSION_MINOR < 7 || \ - _IRR_MATERIAL_MAX_TEXTURES_ < 8 || \ - (!defined(_IRR_COMPILE_WITH_OPENGL_) && \ - !defined(_IRR_COMPILE_WITH_OGLES2_)) || \ - !defined(_IRR_COMPILE_WITH_B3D_LOADER_)) +#if ( IRRLICHT_VERSION_MAJOR < 1 || \ + IRRLICHT_VERSION_MINOR < 7 || \ + _IRR_MATERIAL_MAX_TEXTURES_ < 8 || \ + ( !defined(_IRR_COMPILE_WITH_OPENGL_) && \ + !defined(SERVER_ONLY) && \ + !defined(_IRR_COMPILE_WITH_OGLES2_) ) || \ + !defined(_IRR_COMPILE_WITH_B3D_LOADER_) ) #error "Building against an incompatible Irrlicht. Distros, \ please use the included version." #endif @@ -97,8 +99,9 @@ struct android_app* global_android_app; /** singleton */ IrrDriver *irr_driver = NULL; - +#ifndef SERVER_ONLY GPUTimer m_perf_query[Q_LAST]; +#endif const int MIN_SUPPORTED_HEIGHT = 768; const int MIN_SUPPORTED_WIDTH = 1024; @@ -148,16 +151,19 @@ IrrDriver::IrrDriver() IrrDriver::~IrrDriver() { assert(m_device != NULL); - +#ifndef SERVER_ONLY cleanUnicolorTextures(); +#endif m_device->drop(); m_device = NULL; m_modes.clear(); +#ifndef SERVER_ONLY if (CVS->isGLSL()) { Shaders::destroy(); } +#endif delete m_wind; delete m_renderer; } // ~IrrDriver @@ -167,7 +173,9 @@ IrrDriver::~IrrDriver() */ void IrrDriver::reset() { +#ifndef SERVER_ONLY m_renderer->resetPostProcessing(); +#endif } // reset // ---------------------------------------------------------------------------- @@ -195,15 +203,17 @@ core::array &IrrDriver::getMainSetup() } // getMainSetup // ---------------------------------------------------------------------------- + #ifndef SERVER_ONLY GPUTimer &IrrDriver::getGPUTimer(unsigned i) { return m_perf_query[i]; } // getGPUTimer - +#endif // ---------------------------------------------------------------------------- +#ifndef SERVER_ONLY std::unique_ptr IrrDriver::createRenderTarget(const irr::core::dimension2du &dimension, const std::string &name) { @@ -221,6 +231,7 @@ If window is the root window, returns window. */ Window get_toplevel_parent(Display* display, Window window) { +#ifndef SERVER_ONLY Window parent; Window root; Window * children; @@ -243,6 +254,9 @@ Window get_toplevel_parent(Display* display, Window window) window = parent; } } +#else + return NULL; +#endif } #endif @@ -253,8 +267,9 @@ Window get_toplevel_parent(Display* display, Window window) */ void IrrDriver::updateConfigIfRelevant() { - if (!UserConfigParams::m_fullscreen && - UserConfigParams::m_remember_window_location) +#ifndef SERVER_ONLY + if (!UserConfigParams::m_fullscreen && + UserConfigParams::m_remember_window_location) { #ifdef WIN32 const video::SExposedVideoData& videoData = m_device->getVideoDriver() @@ -306,6 +321,8 @@ void IrrDriver::updateConfigIfRelevant() } #endif } + +#endif // !SERVER_ONLY } // updateConfigIfRelevant // ---------------------------------------------------------------------------- @@ -518,6 +535,7 @@ void IrrDriver::initDevice() { Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting.\n"); } +#ifndef SERVER_ONLY CVS->init(); @@ -536,12 +554,14 @@ void IrrDriver::initDevice() params.ForceLegacyDevice = true; recreate_device = true; } +#endif // This is the ugly hack for intel driver on linux, which doesn't // use sRGB-capable visual, even if we request it. This causes // the screen to be darker than expected. It affects mesa 10.6 and newer. // Though we are able to force to use the proper format on mesa side by // setting WithAlphaChannel parameter. +#ifndef SERVER_ONLY else if (CVS->needsSRGBCapableVisualWorkaround()) { Log::warn("irr_driver", "Created visual is not sRGB-capable. " @@ -567,17 +587,19 @@ void IrrDriver::initDevice() CVS->init(); } +#endif m_scene_manager = m_device->getSceneManager(); m_gui_env = m_device->getGUIEnvironment(); m_video_driver = m_device->getVideoDriver(); m_actual_screen_size = m_video_driver->getCurrentRenderTargetSize(); - +#ifndef SERVER_ONLY if(CVS->isGLSL()) m_renderer = new ShaderBasedRenderer(); else m_renderer = new FixedPipelineRenderer(); +#endif if (UserConfigParams::m_shadows_resolution != 0 && (UserConfigParams::m_shadows_resolution < 512 || @@ -596,6 +618,7 @@ void IrrDriver::initDevice() m_video_driver->beginScene(/*backBuffer clear*/true, /* Z */ false); m_video_driver->endScene(); +#ifndef SERVER_ONLY if (CVS->isGLSL()) { Log::info("irr_driver", "GLSL supported."); @@ -608,6 +631,7 @@ void IrrDriver::initDevice() UserConfigParams::m_gi = false; }*/ + // m_glsl might be reset in rtt if an error occurs. if (CVS->isGLSL()) { @@ -622,11 +646,12 @@ void IrrDriver::initDevice() Log::warn("irr_driver", "Using the fixed pipeline (old GPU, or " "shaders disabled in options)"); } +#endif // Only change video driver settings if we are showing graphics if (!ProfileWorld::isNoGraphics()) { -#if defined(__linux__) && !defined(ANDROID) +#if defined(__linux__) && !defined(ANDROID) && !defined(SERVER_ONLY) // Set class hints on Linux, used by Window Managers. const video::SExposedVideoData& videoData = m_video_driver ->getExposedVideoData(); @@ -676,10 +701,12 @@ void IrrDriver::initDevice() material2D.AntiAliasing=video::EAAM_FULL_BASIC; //m_video_driver->enableMaterial2D(); +#ifndef SERVER_ONLY // set cursor visible by default (what's the default is not too clearly documented, // so let's decide ourselves...) m_device->getCursorControl()->setVisible(true); m_pointer_shown = true; +#endif } // initDevice // ---------------------------------------------------------------------------- @@ -703,6 +730,7 @@ void IrrDriver::cleanSunInterposer() // ---------------------------------------------------------------------------- void IrrDriver::createSunInterposer() { +#ifndef SERVER_ONLY scene::IMesh * sphere = m_scene_manager->getGeometryCreator() ->createSphereMesh(1, 16, 16); for (unsigned i = 0; i < sphere->getMeshBufferCount(); ++i) @@ -731,15 +759,18 @@ void IrrDriver::createSunInterposer() m_sun_interposer->getMaterial(0).MaterialType = Shaders::getShader(ES_OBJECTPASS); sphere->drop(); +#endif } //----------------------------------------------------------------------------- void IrrDriver::getOpenGLData(std::string *vendor, std::string *renderer, std::string *version) { +#ifndef SERVER_ONLY *vendor = (char*)glGetString(GL_VENDOR ); *renderer = (char*)glGetString(GL_RENDERER); *version = (char*)glGetString(GL_VERSION ); +#endif } // getOpenGLData //----------------------------------------------------------------------------- @@ -783,6 +814,7 @@ core::position2di IrrDriver::getMouseLocation() */ bool IrrDriver::moveWindow(int x, int y) { +#ifndef SERVER_ONLY #ifdef WIN32 const video::SExposedVideoData& videoData = m_video_driver->getExposedVideoData(); @@ -821,6 +853,7 @@ bool IrrDriver::moveWindow(int x, int y) // TODO: Actually handle possible failure XMoveWindow(display, videoData.OpenGLLinux.X11Window, x, y); +#endif #endif return true; } @@ -850,6 +883,7 @@ void IrrDriver::changeResolution(const int w, const int h, void IrrDriver::applyResolutionSettings() { +#ifndef SERVER_ONLY // show black before resolution switch so we don't see OpenGL's buffer // garbage during switch m_video_driver->beginScene(true, true, video::SColor(255,100,101,140)); @@ -939,6 +973,7 @@ void IrrDriver::applyResolutionSettings() // above) - this happens dynamically when the tracks are loaded. GUIEngine::reshowCurrentScreen(); MessageQueue::updatePosition(); +#endif // !SERVER_ONLY } // applyResolutionSettings // ---------------------------------------------------------------------------- @@ -1154,6 +1189,7 @@ scene::IMeshSceneNode *IrrDriver::addSphere(float radius, m.EmissiveColor = color; m.BackfaceCulling = false; m.MaterialType = video::EMT_SOLID; +#ifndef SERVER_ONLY //m.setTexture(0, getUnicolorTexture(video::SColor(128, 255, 105, 180))); m.setTexture(0, getUnicolorTexture(color)); m.setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0))); @@ -1167,6 +1203,7 @@ scene::IMeshSceneNode *IrrDriver::addSphere(float radius, NULL, -1, "sphere"); return node; } +#endif scene::IMeshSceneNode *node = m_scene_manager->addMeshSceneNode(mesh); return node; @@ -1192,6 +1229,9 @@ scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh, bool all_parts_colorized, int frame_for_mesh) { +#ifdef SERVER_ONLY + return m_scene_manager->addMeshSceneNode(mesh, parent); +#else if (!CVS->isGLSL()) return m_scene_manager->addMeshSceneNode(mesh, parent); @@ -1210,6 +1250,7 @@ scene::IMeshSceneNode *IrrDriver::addMesh(scene::IMesh *mesh, node->drop(); return node; +#endif } // addMesh // ---------------------------------------------------------------------------- @@ -1233,6 +1274,7 @@ scene::ISceneNode *IrrDriver::addBillboard(const core::dimension2d< f32 > size, bool alphaTesting) { scene::IBillboardSceneNode* node; +#ifndef SERVER_ONLY if (CVS->isGLSL()) { if (!parent) @@ -1243,13 +1285,14 @@ scene::ISceneNode *IrrDriver::addBillboard(const core::dimension2d< f32 > size, node->drop(); } else +#endif node = m_scene_manager->addBillboardSceneNode(parent, size); assert(node->getMaterialCount() > 0); node->setMaterialTexture(0, texture); if(alphaTesting) node->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); return node; -} // addMesh +} // addBillboard // ---------------------------------------------------------------------------- /** Creates a quad mesh with a given material. @@ -1391,13 +1434,16 @@ scene::IAnimatedMeshSceneNode *IrrDriver::addAnimatedMesh(scene::IAnimatedMesh * const std::string& debug_name, scene::ISceneNode* parent, RenderInfo* render_info, bool all_parts_colorized) { +#ifndef SERVER_ONLY if (!CVS->isGLSL()) { +#endif return m_scene_manager->addAnimatedMeshSceneNode(mesh, parent, -1, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), core::vector3df(1, 1, 1), /*addIfMeshIsZero*/true); +#ifndef SERVER_ONLY } if (!parent) @@ -1408,6 +1454,7 @@ scene::IAnimatedMeshSceneNode *IrrDriver::addAnimatedMesh(scene::IAnimatedMesh * core::vector3df(1, 1, 1), render_info, all_parts_colorized); node->drop(); return node; +#endif } // addAnimatedMesh // ---------------------------------------------------------------------------- @@ -1448,19 +1495,24 @@ scene::ISceneNode *IrrDriver::addSkyDome(video::ITexture *texture, scene::ISceneNode *IrrDriver::addSkyBox(const std::vector &texture, const std::vector &spherical_harmonics_textures) { +#ifndef SERVER_ONLY assert(texture.size() == 6); m_renderer->addSkyBox(texture, spherical_harmonics_textures); +#endif return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1], texture[2], texture[3], texture[4], texture[5]); } // addSkyBox +// ---------------------------------------------------------------------------- void IrrDriver::suppressSkyBox() { +#ifndef SERVER_ONLY m_renderer->removeSkyBox();; -} +#endif +} // suppressSkyBox // ---------------------------------------------------------------------------- /** Adds a camera to the scene. @@ -1811,13 +1863,17 @@ video::ITexture* IrrDriver::applyMask(video::ITexture* texture, // ---------------------------------------------------------------------------- void IrrDriver::onLoadWorld() { +#ifndef SERVER_ONLY m_renderer->onLoadWorld(); -} -// ---------------------------------------------------------------------------- +#endif +} // onLoadWorld + + // ---------------------------------------------------------------------------- void IrrDriver::onUnloadWorld() { m_renderer->onUnloadWorld(); -} +} // onUnloadWorld + // ---------------------------------------------------------------------------- /** Sets the ambient light. * \param light The colour of the light to set. @@ -1826,10 +1882,13 @@ void IrrDriver::onUnloadWorld() */ void IrrDriver::setAmbientLight(const video::SColorf &light, bool force_SH_computation) { +#ifndef SERVER_ONLY m_scene_manager->setAmbientLight(light); m_renderer->setAmbientLight(light, force_SH_computation); +#endif } // setAmbientLight +// ---------------------------------------------------------------------------- video::SColorf IrrDriver::getAmbientLight() const { return m_scene_manager->getAmbientLight(); @@ -1840,6 +1899,7 @@ video::SColorf IrrDriver::getAmbientLight() const */ void IrrDriver::displayFPS() { +#ifndef SERVER_ONLY gui::IGUIFont* font = GUIEngine::getSmallFont(); core::rect position; @@ -1911,6 +1971,7 @@ void IrrDriver::displayFPS() static video::SColor fpsColor = video::SColor(255, 0, 0, 0); font->draw( fps_string.c_str(), position, fpsColor, false ); +#endif } // updateFPS // ---------------------------------------------------------------------------- @@ -2009,6 +2070,7 @@ void IrrDriver::update(float dt) if (world) { +#ifndef SERVER_ONLY m_renderer->render(dt); GUIEngine::Screen* current_screen = GUIEngine::getCurrentScreen(); @@ -2025,6 +2087,7 @@ void IrrDriver::update(float dt) debug_drawer->beginNextFrame(); } } +#endif } else { @@ -2094,10 +2157,16 @@ bool IrrDriver::OnEvent(const irr::SEvent &event) // ---------------------------------------------------------------------------- bool IrrDriver::supportsSplatting() { +#ifndef SERVER_ONLY return CVS->isGLSL(); -} +#else + return false; +#endif +} // supportsSplatting // ---------------------------------------------------------------------------- + +#ifndef SERVER_ONLY void IrrDriver::applyObjectPassShader(scene::ISceneNode * const node, bool rimlit) { if (!CVS->isGLSL()) @@ -2175,6 +2244,8 @@ void IrrDriver::applyObjectPassShader() applyObjectPassShader(m_scene_manager->getRootSceneNode()); } +#endif // !SERVER_ONLY + // ---------------------------------------------------------------------------- scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, @@ -2182,6 +2253,7 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, float r, float g, float b, bool sun, scene::ISceneNode* parent) { +#ifndef SERVER_ONLY if (CVS->isGLSL()) { if (parent == NULL) parent = m_scene_manager->getRootSceneNode(); @@ -2218,6 +2290,9 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, light->setRadius(radius); return light; } +#else + return NULL; +#endif } // addLight // ---------------------------------------------------------------------------- diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index c7803d8c8..fc16f4dc8 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -305,8 +305,10 @@ public: void unsetTextureErrorMessage(); class GPUTimer &getGPUTimer(unsigned); +#ifndef SERVER_ONLY std::unique_ptr createRenderTarget(const irr::core::dimension2du &dimension, const std::string &name); +#endif // ------------------------------------------------------------------------ /** Convenience function that loads a texture with default parameters diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index 15fce7127..412f410d4 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -1,22 +1,24 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2015 SuperTuxKart-Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "graphics/lighting_passes.hpp" -#include "config/user_config.hpp" +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// 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 "graphics/lighting_passes.hpp" +#include "config/user_config.hpp" #include "graphics/central_settings.hpp" #include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" @@ -735,3 +737,4 @@ void LightingPasses::renderLightsScatter(GLuint depth_stencil_texture, colors_framebuffer.getHeight()); } // renderLightsScatter +#endif diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index c80d85189..17d87b2f2 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -254,6 +254,7 @@ void LODNode::OnRegisterSceneNode() m_previous_visibility = (shown ? WAS_SHOWN : WAS_HIDDEN); m_last_tick = now; +#ifndef SERVER_ONLY if (!CVS->isGLSL()) { for (core::list::Iterator it = Children.begin(); @@ -262,7 +263,7 @@ void LODNode::OnRegisterSceneNode() (*it)->updateAbsolutePosition(); } } - +#endif scene::ISceneNode::OnRegisterSceneNode(); } @@ -296,5 +297,8 @@ void LODNode::add(int level, scene::ISceneNode* node, bool reparent) node->drop(); node->updateAbsolutePosition(); +#ifndef SERVER_ONLY irr_driver->applyObjectPassShader(node); +#endif } + diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index d89d4d6ac..653a8a43d 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -716,6 +716,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m m_texname.c_str()); } +#ifndef SERVER_ONLY // Backface culling if(!m_backface_culling) m->setFlag(video::EMF_BACK_FACE_CULLING, false); @@ -869,7 +870,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m } m->setTexture(1, glossytex); } - +#endif if (m_shader_type == SHADERTYPE_SOLID_UNLIT) { @@ -1013,6 +1014,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m void Material::adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, bool use_fog) const { +#ifndef SERVER_ONLY if (CVS->isGLSL()) { // to disable fog in the new pipeline, we slightly abuse the steps : @@ -1036,6 +1038,7 @@ void Material::adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, if (parent != NULL) parent->setMaterialFlag(video::EMF_FOG_ENABLE, m_fog && use_fog); } +#endif } // adjustForFog //----------------------------------------------------------------------------- @@ -1043,7 +1046,9 @@ void Material::adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, /** Callback from LOD nodes to create some effects */ void Material::onMadeVisible(scene::IMeshBuffer* who) { +#ifndef SERVER_ONLY if (!CVS->isGLSL()) return; +#endif } //----------------------------------------------------------------------------- @@ -1051,14 +1056,18 @@ void Material::onMadeVisible(scene::IMeshBuffer* who) /** Callback from LOD nodes to create some effects */ void Material::onHidden(scene::IMeshBuffer* who) { +#ifndef SERVER_ONLY if (!CVS->isGLSL()) return; +#endif } //----------------------------------------------------------------------------- void Material::isInitiallyHidden(scene::IMeshBuffer* who) { +#ifndef SERVER_ONLY if (!CVS->isGLSL()) return; +#endif } //----------------------------------------------------------------------------- diff --git a/src/graphics/material_manager.cpp b/src/graphics/material_manager.cpp index 7c227b7e5..1082f9677 100644 --- a/src/graphics/material_manager.cpp +++ b/src/graphics/material_manager.cpp @@ -145,6 +145,7 @@ Material* MaterialManager::getDefaultMaterial(video::E_MATERIAL_TYPE shader_type // Try to find a cleaner way // If graphics are disabled, shaders should not be accessed (getShader // asserts that shaders are initialised). +#ifndef SERVER_ONLY if(!ProfileWorld::isNoGraphics() && CVS->isGLSL() && shader_type == Shaders::getShader(ShaderType::ES_OBJECT_UNLIT)) default_material->setShaderType(Material::SHADERTYPE_SOLID_UNLIT); @@ -156,7 +157,7 @@ Material* MaterialManager::getDefaultMaterial(video::E_MATERIAL_TYPE shader_type // default_material->setShaderType(Material::SHADERTYPE_ALPHA_BLEND); else default_material->setShaderType(Material::SHADERTYPE_SOLID); - +#endif m_default_materials[shader_type] = default_material; return default_material; } diff --git a/src/graphics/materials.cpp b/src/graphics/materials.cpp index 5acbda0fd..385f1568d 100644 --- a/src/graphics/materials.cpp +++ b/src/graphics/materials.cpp @@ -17,6 +17,8 @@ #include "graphics/materials.hpp" +#ifndef SERVER_ONLY + const STK::Tuple DefaultMaterial::FirstPassTextures = STK::Tuple(1); const STK::Tuple DefaultMaterial::SecondPassTextures @@ -84,3 +86,5 @@ const STK::Tuple const STK::Tuple<> SplattingMat::ShadowTextures; const STK::Tuple SplattingMat::RSMTextures = STK::Tuple(1, 3, 4, 5, 6); + +#endif diff --git a/src/graphics/materials.hpp b/src/graphics/materials.hpp index 99f7ff739..fd8abfe91 100644 --- a/src/graphics/materials.hpp +++ b/src/graphics/materials.hpp @@ -18,6 +18,8 @@ #ifndef HEADER_MATERIAL_TYPE_HPP #define HEADER_MATERIAL_TYPE_HPP +#ifndef SERVER_ONLY + #include "graphics/shader.hpp" #include "graphics/shaders.hpp" #include "graphics/stk_mesh.hpp" @@ -871,4 +873,5 @@ struct SplattingMat }; // SplattingMat -#endif //HEADER_MATERIAL_TYPE_HPP +#endif // !SERVER_ONLY +#endif // HEADER_MATERIAL_TYPE_HPP diff --git a/src/graphics/mesh_tools.cpp b/src/graphics/mesh_tools.cpp index 95bf286ee..cbc1f83a7 100644 --- a/src/graphics/mesh_tools.cpp +++ b/src/graphics/mesh_tools.cpp @@ -328,6 +328,7 @@ void recalculateTangents(scene::IMesh* mesh, bool recalculate_normals, bool smoo } } +#ifndef SERVER_ONLY bool MeshTools::isNormalMap(scene::IMeshBuffer* mb) { if (!CVS->isGLSL()) @@ -335,6 +336,7 @@ bool MeshTools::isNormalMap(scene::IMeshBuffer* mb) return (mb->getMaterial().MaterialType == Shaders::getShader(ES_NORMAL_MAP) && mb->getVertexType() != video::EVT_TANGENTS); } +#endif // Copied from irrlicht scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh, diff --git a/src/graphics/particle_emitter.cpp b/src/graphics/particle_emitter.cpp index cfc4e584e..dae6c5bdf 100644 --- a/src/graphics/particle_emitter.cpp +++ b/src/graphics/particle_emitter.cpp @@ -16,6 +16,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 "graphics/particle_emitter.hpp" #include "graphics/central_settings.hpp" @@ -764,3 +766,5 @@ void ParticleEmitter::resizeBox(float size) } #endif } + +#endif // !SERVER_ONLY diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 0ba63e6d0..fbdbceb33 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.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 "graphics/post_processing.hpp" #include "config/user_config.hpp" @@ -1597,3 +1599,5 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, return out_fbo; } // render + +#endif // !SERVER_ONLY diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index 4b60ddf53..3e1cd8962 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -147,7 +147,7 @@ Referee::Referee() m_scene_node->setScale(m_st_scale.toIrrVector()); m_scene_node->setFrameLoop(m_st_first_start_frame, m_st_last_start_frame); - +#ifndef SERVER_ONLY irr_driver->applyObjectPassShader(m_scene_node); if (CVS->isGLSL() && CVS->isDefferedEnabled()) @@ -156,6 +156,7 @@ Referee::Referee() 0.7f /* r */, 0.0 /* g */, 0.0f /* b */, false /* sun */, m_scene_node); } else +#endif { m_light = NULL; } @@ -184,7 +185,9 @@ Referee::Referee(const AbstractKart &kart) m_scene_node->setFrameLoop(m_st_first_rescue_frame, m_st_last_rescue_frame); +#ifndef SERVER_ONLY irr_driver->applyObjectPassShader(m_scene_node); +#endif } // Referee // ---------------------------------------------------------------------------- diff --git a/src/graphics/render_target.cpp b/src/graphics/render_target.cpp index e9e45b64c..b15c21004 100644 --- a/src/graphics/render_target.cpp +++ b/src/graphics/render_target.cpp @@ -15,6 +15,7 @@ // 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 "graphics/render_target.hpp" #include "graphics/2dutils.hpp" @@ -151,3 +152,5 @@ void GL3RenderTarget::draw2DImage(const irr::core::rect& dest_rect, glDisable(GL_FRAMEBUFFER_SRGB); } // draw2DImage + +#endif // !SERVER_ONLY \ No newline at end of file diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp index ab60d7654..090bacd32 100644 --- a/src/graphics/rtts.cpp +++ b/src/graphics/rtts.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 "graphics/rtts.hpp" #include "config/user_config.hpp" @@ -58,14 +60,14 @@ RTT::RTT(size_t width, size_t height) using namespace video; using namespace core; - dimension2du res(width * UserConfigParams::m_scale_rtts_factor, - height * UserConfigParams::m_scale_rtts_factor); + dimension2du res(int(width * UserConfigParams::m_scale_rtts_factor), + int(height * UserConfigParams::m_scale_rtts_factor) ); const dimension2du half = res/2; const dimension2du quarter = res/4; const dimension2du eighth = res/8; - const u16 shadowside = 1024 * UserConfigParams::m_scale_rtts_factor; + const u16 shadowside = u16(1024 * UserConfigParams::m_scale_rtts_factor); const dimension2du shadowsize0(shadowside, shadowside); const dimension2du shadowsize1(shadowside / 2, shadowside / 2); const dimension2du shadowsize2(shadowside / 4, shadowside / 4); @@ -350,3 +352,5 @@ RTT::~RTT() } } + +#endif // !SERVER_ONLY diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index fd4864777..951c4ed13 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -16,6 +16,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 "graphics/shader.hpp" #include "graphics/central_settings.hpp" @@ -362,3 +364,5 @@ GLuint ShaderBase::createVAO() } // createVAO // ============================================================================ + +#endif // !SERVER_ONLY diff --git a/src/graphics/shader.hpp b/src/graphics/shader.hpp index 785075f2d..8e6ab5e93 100644 --- a/src/graphics/shader.hpp +++ b/src/graphics/shader.hpp @@ -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 + #ifndef HEADER_SHADER_HPP #define HEADER_SHADER_HPP @@ -383,3 +385,6 @@ public: // ============================================================================ #endif + +#endif // !SERVER_ONLY + diff --git a/src/graphics/shader_based_renderer.cpp b/src/graphics/shader_based_renderer.cpp index 140635edb..380877256 100644 --- a/src/graphics/shader_based_renderer.cpp +++ b/src/graphics/shader_based_renderer.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 "graphics/shader_based_renderer.hpp" #include "config/user_config.hpp" @@ -957,3 +959,5 @@ void ShaderBasedRenderer::renderToTexture(GL3RenderTarget *render_target, irr_driver->getSceneManager()->setActiveCamera(NULL); } //renderToTexture + +#endif // !SERVER_ONLY diff --git a/src/graphics/shader_based_renderer.hpp b/src/graphics/shader_based_renderer.hpp index 62a827cf3..e5e33752d 100644 --- a/src/graphics/shader_based_renderer.hpp +++ b/src/graphics/shader_based_renderer.hpp @@ -18,6 +18,8 @@ #ifndef HEADER_SHADER_BASED_RENDERER_HPP #define HEADER_SHADER_BASED_RENDERER_HPP +#ifndef SERVER_ONLY + #include "graphics/abstract_renderer.hpp" #include "graphics/draw_calls.hpp" #include "graphics/lighting_passes.hpp" @@ -125,4 +127,5 @@ public: }; -#endif //HEADER_SHADER_BASED_RENDERER_HPP +#endif // !SERVER_ONLY +#endif // HEADER_SHADER_BASED_RENDERER_HPP diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index b42b8d4f8..577798b38 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -16,6 +16,8 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef SERVER_ONLY + /** \page shaders_overview Shaders Overview @@ -421,3 +423,5 @@ Shaders::ColoredLine::ColoredLine() glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } // Shaders::ColoredLine + +#endif // !SERVER_ONLY diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 820c4a78f..263b8d99d 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -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 + #ifndef HEADER_SHADERS_HPP #define HEADER_SHADERS_HPP @@ -176,3 +178,5 @@ public: }; // class Shaders #endif + +#endif // SHADER_ONLY diff --git a/src/graphics/shadow_matrices.cpp b/src/graphics/shadow_matrices.cpp index d67f006ac..ceff5a5f4 100644 --- a/src/graphics/shadow_matrices.cpp +++ b/src/graphics/shadow_matrices.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 "graphics/shadow_matrices.hpp" #include "config/user_config.hpp" @@ -523,3 +525,5 @@ void ShadowMatrices::renderShadowsDebug(const FrameBuffer &shadow_framebuffer, renderWireFrameFrustrum(m_shadows_cam[3], 3); glViewport(0, 0, UserConfigParams::m_width, UserConfigParams::m_height); } + +#endif // !SERVER_ONLY diff --git a/src/graphics/shared_gpu_objects.cpp b/src/graphics/shared_gpu_objects.cpp index 85b56a60f..06836f29d 100644 --- a/src/graphics/shared_gpu_objects.cpp +++ b/src/graphics/shared_gpu_objects.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 "graphics/shared_gpu_objects.hpp" #include "graphics/central_settings.hpp" @@ -232,3 +234,6 @@ void SharedGPUObjects::reset() { m_has_been_initialised = false; } // reset + +#endif // !SERVER_ONLY + diff --git a/src/graphics/show_curve.cpp b/src/graphics/show_curve.cpp index 39eea68b7..b2abf2d3b 100644 --- a/src/graphics/show_curve.cpp +++ b/src/graphics/show_curve.cpp @@ -16,6 +16,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 "graphics/show_curve.hpp" #include "graphics/irr_driver.hpp" @@ -200,3 +202,6 @@ void ShowCurve::setPosition(const Vec3 &xyz) m_scene_node->setPosition(xyz.toIrrVector()); } // setPosition // ---------------------------------------------------------------------------- + +#endif // !SERVER_ONLY + diff --git a/src/graphics/skid_marks.cpp b/src/graphics/skid_marks.cpp index 48dcf1a74..22b6b493a 100644 --- a/src/graphics/skid_marks.cpp +++ b/src/graphics/skid_marks.cpp @@ -131,12 +131,14 @@ void SkidMarks::update(float dt, bool force_skid_marks, if (!is_skidding) // end skid marking { m_skid_marking = false; +#ifndef SERVER_ONLY // The vertices and indices will not change anymore // (till these skid mark quads are deleted) m_left[m_current]->setHardwareMappingHint(scene::EHM_STATIC); m_right[m_current]->setHardwareMappingHint(scene::EHM_STATIC); if (STKMeshSceneNode* stkm = dynamic_cast(m_nodes[m_current])) stkm->setReloadEachFrame(false); +#endif return; } @@ -192,11 +194,13 @@ void SkidMarks::update(float dt, bool force_skid_marks, custom_color); new_mesh->addMeshBuffer(smq_right); scene::IMeshSceneNode *new_node = irr_driver->addMesh(new_mesh, "skidmark"); +#ifndef SERVER_ONLY if (STKMeshSceneNode* stkm = dynamic_cast(new_node)) stkm->setReloadEachFrame(true); #ifdef DEBUG std::string debug_name = m_kart.getIdent()+" (skid-mark)"; new_node->setName(debug_name.c_str()); +#endif #endif // We don't keep a reference to the mesh here, so we have to decrement diff --git a/src/graphics/skybox.cpp b/src/graphics/skybox.cpp index 2eda7d50d..fd1c597b8 100644 --- a/src/graphics/skybox.cpp +++ b/src/graphics/skybox.cpp @@ -15,6 +15,7 @@ // 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 "graphics/skybox.hpp" #include "graphics/central_settings.hpp" @@ -375,4 +376,5 @@ void Skybox::render(const scene::ICameraSceneNode *camera) const glBindVertexArray(0); } // renderSkybox +#endif // !SERVER_ONLY diff --git a/src/graphics/slip_stream.cpp b/src/graphics/slip_stream.cpp index eb588f02a..5ced96ad9 100644 --- a/src/graphics/slip_stream.cpp +++ b/src/graphics/slip_stream.cpp @@ -51,10 +51,12 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart) scene::IMeshBuffer* buffer = m_mesh->getMeshBuffer(0); material->setMaterialProperties(&buffer->getMaterial(), buffer); +#ifndef SERVER_ONLY STKMeshSceneNode* stk_node = dynamic_cast(m_node); if (stk_node != NULL) stk_node->setReloadEachFrame(true); m_mesh->drop(); +#endif #ifdef DEBUG std::string debug_name = m_kart->getIdent()+" (slip-stream)"; @@ -99,8 +101,10 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart) } video::SMaterial &mat = buffer->getMaterial(); // Meshes need a texture, otherwise stk crashes. +#ifndef SERVER_ONLY video::ITexture *red_texture = getUnicolorTexture(red); mat.setTexture(0, red_texture); +#endif buffer->recalculateBoundingBox(); m_mesh->setBoundingBox(buffer->getBoundingBox()); @@ -231,7 +235,9 @@ void SlipStream::createMesh(Material* material) } // for jsetMaterialProperties(&buffer->getMaterial(), buffer); +#ifndef SERVER_ONLY if (!CVS->isGLSL()) +#endif { buffer->Material.setFlag(video::EMF_BACK_FACE_CULLING, false); buffer->Material.setFlag(video::EMF_COLOR_MATERIAL, true); diff --git a/src/graphics/spherical_harmonics.cpp b/src/graphics/spherical_harmonics.cpp index 15d07aab4..0d1f0657b 100644 --- a/src/graphics/spherical_harmonics.cpp +++ b/src/graphics/spherical_harmonics.cpp @@ -15,6 +15,7 @@ // 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 "graphics/irr_driver.hpp" #include "graphics/spherical_harmonics.hpp" @@ -528,3 +529,5 @@ void SphericalHarmonics::unprojectSH(size_t width, size_t height, } } // unprojectSH +#endif // !SERVER_ONLY + diff --git a/src/graphics/stk_animated_mesh.cpp b/src/graphics/stk_animated_mesh.cpp index c262372d9..d06a375c6 100644 --- a/src/graphics/stk_animated_mesh.cpp +++ b/src/graphics/stk_animated_mesh.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 "graphics/stk_animated_mesh.hpp" #include "graphics/central_settings.hpp" @@ -344,3 +346,5 @@ void STKAnimatedMesh::resetSkinningState(scene::IAnimatedMesh* mesh) m_skinned_mesh = NULL; } } + +#endif // !SERVER_ONLY diff --git a/src/graphics/stk_billboard.cpp b/src/graphics/stk_billboard.cpp index 4d770e455..573a0348b 100644 --- a/src/graphics/stk_billboard.cpp +++ b/src/graphics/stk_billboard.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 "graphics/stk_billboard.hpp" #include "graphics/irr_driver.hpp" @@ -118,3 +120,6 @@ void STKBillboard::render() glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindVertexArray(0); } // render + +#endif // !SERVER_ONLY + diff --git a/src/graphics/stk_mesh.cpp b/src/graphics/stk_mesh.cpp index c8bf040b1..2ce4e23a0 100644 --- a/src/graphics/stk_mesh.cpp +++ b/src/graphics/stk_mesh.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 "graphics/stk_mesh.hpp" #include "graphics/callbacks.hpp" @@ -471,3 +473,6 @@ void initTexturesTransparent(GLMesh &mesh) } #endif } // initTexturesTransparent + +#endif // !SERVER_ONLY + diff --git a/src/graphics/stk_mesh_scene_node.cpp b/src/graphics/stk_mesh_scene_node.cpp index d2b3244e8..92a0a6cc8 100644 --- a/src/graphics/stk_mesh_scene_node.cpp +++ b/src/graphics/stk_mesh_scene_node.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 "graphics/stk_mesh_scene_node.hpp" #include "graphics/central_settings.hpp" @@ -608,3 +610,6 @@ void STKMeshSceneNode::render() } } } + +#endif // !SERVER_ONLY + diff --git a/src/graphics/stk_mesh_scene_node.hpp b/src/graphics/stk_mesh_scene_node.hpp index 07fc4030f..c75e52d00 100644 --- a/src/graphics/stk_mesh_scene_node.hpp +++ b/src/graphics/stk_mesh_scene_node.hpp @@ -73,8 +73,10 @@ public: scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); if (!mb) continue; +#ifndef SERVER_ONLY if (isDisplacement) mb->getMaterial().MaterialType = Shaders::getShader(ES_DISPLACE); +#endif } } virtual bool glow() const { return isGlow; } diff --git a/src/graphics/stk_scene_manager.cpp b/src/graphics/stk_scene_manager.cpp new file mode 100644 index 000000000..b26181ab8 --- /dev/null +++ b/src/graphics/stk_scene_manager.cpp @@ -0,0 +1,67 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014-2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// 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 "graphics/stk_scene_manager.hpp" +#include +#include + +using namespace irr; + +// From irrlicht code +static +bool isBoxInFrontOfPlane(const core::plane3df &plane, const core::vector3df edges[8]) +{ + for (u32 j = 0; j<8; ++j) + if (plane.classifyPointRelation(edges[j]) != core::ISREL3D_FRONT) + return false; + return true; +} + +std::vector BoundingBoxes; + +void addEdge(const core::vector3df &P0, const core::vector3df &P1) +{ + BoundingBoxes.push_back(P0.X); + BoundingBoxes.push_back(P0.Y); + BoundingBoxes.push_back(P0.Z); + BoundingBoxes.push_back(P1.X); + BoundingBoxes.push_back(P1.Y); + BoundingBoxes.push_back(P1.Z); +} + +bool isCulledPrecise(const scene::ICameraSceneNode *cam, const scene::ISceneNode *node) +{ + if (!node->getAutomaticCulling()) + return false; + + const core::matrix4 &trans = node->getAbsoluteTransformation(); + const scene::SViewFrustum &frust = *cam->getViewFrustum(); + + core::vector3df edges[8]; + node->getBoundingBox().getEdges(edges); + for (unsigned i = 0; i < 8; i++) + trans.transformVect(edges[i]); + + for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i) + if (isBoxInFrontOfPlane(frust.planes[i], edges)) + return true; + return false; +} + +#endif // !SERVER_ONLY diff --git a/src/graphics/stk_scene_manager.hpp b/src/graphics/stk_scene_manager.hpp new file mode 100644 index 000000000..8fc984b6a --- /dev/null +++ b/src/graphics/stk_scene_manager.hpp @@ -0,0 +1,37 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014-2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +// Not really a scene manager yet but hold algorithm that +// rework scene manager output + +#ifndef SERVER_ONLY + +#ifndef HEADER_STKSCENEMANAGER_HPP +#define HEADER_STKSCENEMANAGER_HPP + +#include +#include +#include + +void addEdge(const irr::core::vector3df &P0, const irr::core::vector3df &P1); + +bool isCulledPrecise(const irr::scene::ICameraSceneNode *cam, const irr::scene::ISceneNode *node); + +#endif + +#endif // supertuxkart diff --git a/src/graphics/stk_text_billboard.cpp b/src/graphics/stk_text_billboard.cpp index b99f4500b..efaa002cc 100644 --- a/src/graphics/stk_text_billboard.cpp +++ b/src/graphics/stk_text_billboard.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 "graphics/stk_text_billboard.hpp" #include "graphics/shaders.hpp" #include "graphics/irr_driver.hpp" @@ -190,3 +192,6 @@ void STKTextBillboard::collectChar(video::ITexture* texture, { m_chars.push_back(STKTextBillboardChar(texture, destRect, sourceRect, colors)); } + +#endif // !SERVER_ONLY + diff --git a/src/graphics/texture_manager.cpp b/src/graphics/texture_manager.cpp index 1a2d25a29..73ad87f03 100644 --- a/src/graphics/texture_manager.cpp +++ b/src/graphics/texture_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 "graphics/texture_manager.hpp" #include "graphics/central_settings.hpp" @@ -277,3 +279,6 @@ video::ITexture* getUnicolorTexture(const video::SColor &c) return tex; } } + +#endif // !SERVER_ONLY + diff --git a/src/graphics/texture_shader.cpp b/src/graphics/texture_shader.cpp index e4de23ae8..339434ae8 100644 --- a/src/graphics/texture_shader.cpp +++ b/src/graphics/texture_shader.cpp @@ -16,6 +16,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 "graphics/texture_shader.hpp" #include "graphics/central_settings.hpp" @@ -366,3 +368,6 @@ GLuint TextureShaderBase::createSemiTrilinearSampler() // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- + +#endif // !SERVER_ONLY + diff --git a/src/graphics/texture_shader.hpp b/src/graphics/texture_shader.hpp index 54180cd17..5c1c3a128 100644 --- a/src/graphics/texture_shader.hpp +++ b/src/graphics/texture_shader.hpp @@ -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 SHADER_ONLY + #ifndef HEADER_TEXTURE_SHADER_HPP #define HEADER_TEXTURE_SHADER_HPP @@ -259,3 +261,5 @@ public: }; // class TextureShader #endif + +#endif // SHADER_ONLY diff --git a/src/graphics/vao_manager.cpp b/src/graphics/vao_manager.cpp index 7e880da3f..9cc278e2a 100644 --- a/src/graphics/vao_manager.cpp +++ b/src/graphics/vao_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 "graphics/vao_manager.hpp" #include "graphics/central_settings.hpp" @@ -367,3 +369,5 @@ std::pair VAOManager::getBase(scene::IMeshBuffer *mb, Render assert(It != mappedBaseIndex[tp].end()); return std::pair(vtx, It->second); } + +#endif // !SERVER_ONLY diff --git a/src/graphics/water.cpp b/src/graphics/water.cpp index f8130aaeb..5f587cf39 100644 --- a/src/graphics/water.cpp +++ b/src/graphics/water.cpp @@ -16,6 +16,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 "graphics/water.hpp" #include "graphics/callbacks.hpp" @@ -89,3 +91,6 @@ void WaterNode::OnRegisterSceneNode() ISceneNode::OnRegisterSceneNode(); } } + +#endif // !SERVER_ONLY + diff --git a/src/guiengine/CGUISpriteBank.cpp b/src/guiengine/CGUISpriteBank.cpp index 45b30070f..6c1098acc 100644 --- a/src/guiengine/CGUISpriteBank.cpp +++ b/src/guiengine/CGUISpriteBank.cpp @@ -174,6 +174,7 @@ void STKModifiedSpriteBank::draw2DSprite(u32 index, const core::rect* clip, const video::SColor& color, u32 starttime, u32 currenttime, bool loop, bool center) { +#ifndef SERVER_ONLY assert( m_magic_number == 0xCAFEC001 ); if (index >= Sprites.size() || Sprites[index].Frames.empty() ) return; @@ -221,7 +222,7 @@ void STKModifiedSpriteBank::draw2DSprite(u32 index, */ draw2DImage(tex, dest, r /* source rect */, clip, NULL /* colors */, true); - +#endif } // draw2DSprite // ---------------------------------------------------------------------------- diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index c627d7e89..6f225b548 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -664,7 +664,9 @@ namespace GUIEngine #include "font/regular_face.hpp" #include "input/input_manager.hpp" #include "io/file_manager.hpp" +#ifndef SERVER_ONLY #include "graphics/2dutils.hpp" +#endif #include "graphics/irr_driver.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/modaldialog.hpp" @@ -1121,6 +1123,7 @@ namespace GUIEngine void render(float elapsed_time) { +#ifndef SERVER_ONLY GUIEngine::dt = elapsed_time; // Not yet initialized, or already cleaned up @@ -1208,7 +1211,6 @@ namespace GUIEngine y_from - count*text_height), core::dimension2d(screen_size.Width, text_height) ); - GL32_draw2DRectangle(SColor(255,252,248,230), msgRect); Private::g_font->draw((*it).m_message.c_str(), @@ -1244,7 +1246,7 @@ namespace GUIEngine DemoWorld::resetIdleTime(); } - +#endif } // render // ----------------------------------------------------------------------- @@ -1252,6 +1254,7 @@ namespace GUIEngine void renderLoading(bool clearIcons) { +#ifndef SERVER_ONLY if (clearIcons) g_loading_icons.clear(); g_skin->drawBgImage(); @@ -1315,7 +1318,7 @@ namespace GUIEngine x = ICON_MARGIN; } } - +#endif } // renderLoading // ----------------------------------------------------------------------- diff --git a/src/guiengine/scalable_font.cpp b/src/guiengine/scalable_font.cpp index 331cc6ed8..037941d4a 100644 --- a/src/guiengine/scalable_font.cpp +++ b/src/guiengine/scalable_font.cpp @@ -93,6 +93,8 @@ void ScalableFont::draw(const core::stringw& text, const video::SColor& color, bool hcenter, bool vcenter, const core::rect* clip, bool ignoreRTL) { +#ifndef SERVER_ONLY + bool previousRTL = m_font_settings->isRTL(); if (ignoreRTL) m_font_settings->setRTL(false); @@ -102,7 +104,7 @@ void ScalableFont::draw(const core::stringw& text, if (ignoreRTL) m_font_settings->setRTL(previousRTL); - +#endif } // draw // ---------------------------------------------------------------------------- diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 62678a3ed..3475239bf 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -326,7 +326,7 @@ Skin::~Skin() // ---------------------------------------------------------------------------- void Skin::drawBgImage() { - +#ifndef SERVER_ONLY // ---- background image // on one end, making these static is not too clean. // on another end, these variables are really only used locally, @@ -370,6 +370,7 @@ void Skin::drawBgImage() /* no clipping */0, /*color*/ 0, /*alpha*/false); irr_driver->getVideoDriver()->enableMaterial2D(false); +#endif } // drawBgImage // ---------------------------------------------------------------------------- @@ -401,6 +402,7 @@ void Skin::drawBoxFromStretchableTexture(SkinWidgetContainer* w, bool deactivated, const core::recti* clipRect) { +#ifndef SERVER_ONLY // check if widget moved. if so, recalculate coords if (w->m_skin_x != dest.UpperLeftCorner.X || w->m_skin_y != dest.UpperLeftCorner.Y || @@ -701,7 +703,7 @@ X##_yflip.LowerRightCorner.Y = w->m_skin_dest_y + \ { delete[] colorptr; } - +#endif } // drawBoxFromStretchableTexture // ---------------------------------------------------------------------------- @@ -844,6 +846,7 @@ void Skin::drawProgress(Widget* w, const core::recti &rect, void Skin::drawRatingBar(Widget *w, const core::recti &rect, const bool pressed, const bool focused) { +#ifndef SERVER_ONLY RatingBarWidget *ratingBar = (RatingBarWidget*)w; const ITexture *texture = SkinConfig::m_render_params["rating::neutral"].getImage(); @@ -897,7 +900,7 @@ void Skin::drawRatingBar(Widget *w, const core::recti &rect, (w->m_deactivated || ID_DEBUG) ? colors : 0, true /* alpha */); } - +#endif } // drawRatingBar // ---------------------------------------------------------------------------- @@ -921,6 +924,7 @@ void Skin::drawRibbon(const core::recti &rect, Widget* widget, void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, const bool pressed, bool focused) { +#ifndef SERVER_ONLY // for now, when this kind of widget is disabled, just hide it. we can // change that behaviour if we ever need to... //if (widget->m_deactivated) return; @@ -1220,6 +1224,7 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, m_tooltips.push_back(widget); } } +#endif } // drawRibbonChild // ---------------------------------------------------------------------------- @@ -1435,6 +1440,7 @@ void Skin::drawSpinnerChild(const core::recti &rect, Widget* widget, void Skin::drawIconButton(const core::recti &rect, Widget* widget, const bool pressed, bool focused) { +#ifndef SERVER_ONLY RibbonWidget* parentRibbon = dynamic_cast(widget->m_event_handler); IGUIElement* focusedElem = NULL; if (GUIEngine::getFocusForPlayer(PLAYER_ID_GAME_MASTER) != NULL) @@ -1543,6 +1549,7 @@ void Skin::drawIconButton(const core::recti &rect, Widget* widget, { irr_driver->getVideoDriver()->enableMaterial2D(); } +#endif } // drawIconButton // ---------------------------------------------------------------------------- @@ -1662,6 +1669,7 @@ void Skin::drawListSelection(const core::recti &rect, Widget* widget, void Skin::drawListHeader(const irr::core::rect< irr::s32 > &rect, Widget* widget) { +#ifndef SERVER_ONLY bool isSelected = (((ListWidget*)widget->m_event_handler)->m_selected_column == widget && ((ListWidget*)widget->m_event_handler)->m_sort_default == false); @@ -1689,7 +1697,7 @@ void Skin::drawListHeader(const irr::core::rect< irr::s32 > &rect, draw2DImage(img, destRect, srcRect, NULL, NULL, /* alpha */true); } - +#endif } // drawListHeader // ---------------------------------------------------------------------------- @@ -1698,6 +1706,7 @@ void Skin::drawListHeader(const irr::core::rect< irr::s32 > &rect, */ void Skin::renderSections(PtrVector* within_vector) { +#ifndef SERVER_ONLY if (within_vector == NULL) within_vector = &getCurrentScreen()->m_widgets; const unsigned short widgets_amount = within_vector->size(); @@ -1770,12 +1779,13 @@ void Skin::renderSections(PtrVector* within_vector) } } } // next - +#endif // !SERVER_ONLY } // renderSections // ---------------------------------------------------------------------------- void Skin::drawScrollbarBackground(const irr::core::rect< irr::s32 > &rect) { +#ifndef SERVER_ONLY // leave square space at both ends for up/down buttons (yeah, irrlicht // doesn't handle that) core::recti rect2 = rect; @@ -1789,12 +1799,13 @@ void Skin::drawScrollbarBackground(const irr::core::rect< irr::s32 > &rect) p.m_source_area_center, 0 /* no clipping */, 0, true /* alpha */); - +#endif } // drawScrollbarBackground // ---------------------------------------------------------------------------- void Skin::drawScrollbarThumb(const irr::core::rect< irr::s32 > &rect) { +#ifndef SERVER_ONLY BoxRenderParams& p = SkinConfig::m_render_params["scrollbar_thumb::neutral"]; @@ -1802,7 +1813,7 @@ void Skin::drawScrollbarThumb(const irr::core::rect< irr::s32 > &rect) p.m_source_area_center, 0 /* no clipping */, 0, true /* alpha */); - +#endif } // drawScrollbarThumb // ---------------------------------------------------------------------------- @@ -1958,7 +1969,9 @@ void Skin::process3DPane(IGUIElement *element, const core::recti &rect, else if (type == WTYPE_MODEL_VIEW) { ModelViewWidget* mvw = dynamic_cast(widget); +#ifndef SERVER_ONLY mvw->drawRTTScene(rect); +#endif } else if (type == WTYPE_ICON_BUTTON) { @@ -2016,6 +2029,7 @@ void Skin::process3DPane(IGUIElement *element, const core::recti &rect, void doDrawBadge(ITexture* texture, const core::recti& rect, float max_icon_size, bool badge_at_left) { +#ifndef SERVER_ONLY // In case of a problem if(!texture) return; @@ -2041,6 +2055,7 @@ void doDrawBadge(ITexture* texture, const core::recti& rect, draw2DImage(texture, rect2, source_area, 0 /* no clipping */, 0, true /* alpha */); +#endif } // doDrawBadge // ---------------------------------------------------------------------------- @@ -2139,6 +2154,7 @@ void Skin::draw3DSunkenPane (IGUIElement *element, video::SColor bgcolor, bool flat, bool fillBackGround, const core::recti &rect, const core::recti *clip) { +#ifndef SERVER_ONLY const int id = element->getID(); Widget* widget = GUIEngine::getWidget(id); @@ -2257,18 +2273,21 @@ void Skin::draw3DSunkenPane (IGUIElement *element, video::SColor bgcolor, return; } +#endif } // draw3DSunkenPane // ----------------------------------------------------------------------------- void Skin::drawBGFadeColor() { +#ifndef SERVER_ONLY // fade out background SColor color = SkinConfig::m_colors["dialog_background::neutral"]; if (m_dialog_size < 1.0f) color.setAlpha( (unsigned int)(color.getAlpha()*m_dialog_size )); GL32_draw2DRectangle(color, core::recti(position2d< s32 >(0,0), irr_driver->getActualScreenSize())); +#endif } // drawBGFadeColor // ----------------------------------------------------------------------------- @@ -2316,8 +2335,10 @@ core::recti Skin::draw3DWindowBackground(IGUIElement *element, void Skin::draw3DMenuPane (IGUIElement *element, const core::recti &rect, const core::recti *clip) { +#ifndef SERVER_ONLY SColor color = SColor(150, 96, 74, 196); GL32_draw2DRectangle(color, rect); +#endif } // draw3DMenuPane // ----------------------------------------------------------------------------- @@ -2376,7 +2397,9 @@ void Skin::draw2DImage(const video::ITexture* texture, const core::rect& de const core::rect& sourceRect, const core::rect* clipRect, const video::SColor* const colors, bool useAlphaChannelOfTexture) { +#ifndef SERVER_ONLY ::draw2DImage(texture, destRect, sourceRect, clipRect, colors, useAlphaChannelOfTexture); +#endif } // ----------------------------------------------------------------------------- diff --git a/src/guiengine/widgets/CGUIEditBox.cpp b/src/guiengine/widgets/CGUIEditBox.cpp index 73cbeae3b..53012e958 100644 --- a/src/guiengine/widgets/CGUIEditBox.cpp +++ b/src/guiengine/widgets/CGUIEditBox.cpp @@ -99,6 +99,7 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, //! destructor CGUIEditBox::~CGUIEditBox() { +#ifndef SERVER_ONLY if (OverrideFont) OverrideFont->drop(); @@ -108,6 +109,7 @@ CGUIEditBox::~CGUIEditBox() CIrrDeviceLinux* dl = dynamic_cast(irr_driver->getDevice()); dl->setIMEEnable(false); #endif +#endif } @@ -235,6 +237,7 @@ void CGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT ver //! called if an event happened. bool CGUIEditBox::OnEvent(const SEvent& event) { +#ifndef SERVER_ONLY if (isEnabled()) { @@ -280,7 +283,7 @@ bool CGUIEditBox::OnEvent(const SEvent& event) break; } } - +#endif return IGUIElement::OnEvent(event); } @@ -903,6 +906,7 @@ core::position2di CGUIEditBox::calculateICPos() //! draws the element and its children void CGUIEditBox::draw() { +#ifndef SERVER_ONLY if (!IsVisible) return; @@ -1104,6 +1108,7 @@ void CGUIEditBox::draw() // draw children IGUIElement::draw(); +#endif } @@ -1563,6 +1568,7 @@ void CGUIEditBox::inputChar(wchar_t c) void CGUIEditBox::calculateScrollPos() { +#ifndef SERVER_ONLY if (!AutoScroll) return; @@ -1616,6 +1622,7 @@ void CGUIEditBox::calculateScrollPos() dl->setIMELocation(calculateICPos()); } #endif +#endif // SERVER_ONLY } //! set text markers diff --git a/src/guiengine/widgets/model_view_widget.cpp b/src/guiengine/widgets/model_view_widget.cpp index 17ba7e1d9..fe4efb57d 100644 --- a/src/guiengine/widgets/model_view_widget.cpp +++ b/src/guiengine/widgets/model_view_widget.cpp @@ -52,13 +52,17 @@ IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, false, m_properties[PROP_ICON]="gui/main_help.png"; m_rtt_unsupported = false; -} +} // ModelViewWidget + // ----------------------------------------------------------------------------- ModelViewWidget::~ModelViewWidget() { GUIEngine::needsUpdate.remove(this); +#ifndef SERVER_ONLY delete m_render_info; -} +#endif +} // ~ModelViewWidget + // ----------------------------------------------------------------------------- void ModelViewWidget::add() { @@ -92,7 +96,7 @@ void ModelViewWidget::clearModels() m_rtt_main_node = NULL; m_camera = NULL; m_light = NULL; -} +} // clearModels // ----------------------------------------------------------------------------- @@ -107,10 +111,11 @@ void ModelViewWidget::addModel(irr::scene::IMesh* mesh, const Vec3& location, m_model_scale.push_back(scale); m_model_frames.push_back(frame); m_model_render_info_affected.push_back(all_parts_colorized); - +#ifndef SERVER_ONLY if (!CVS->isGLSL()) m_render_target = NULL; -} +#endif +} // addModel // ----------------------------------------------------------------------------- void ModelViewWidget::update(float delta) @@ -161,7 +166,10 @@ void ModelViewWidget::update(float delta) // stop rotating when target reached if (fabsf(m_angle - m_rotation_target) < 2.0f) m_rotation_mode = ROTATE_OFF; } - + +#ifdef SERVER_ONLY + return; +#else if (m_render_target == NULL) { std::string name = "model view "; @@ -181,10 +189,13 @@ void ModelViewWidget::update(float delta) m_render_target->renderToTexture(m_camera, GUIEngine::getLatestDt()); m_rtt_main_node->setVisible(false); -} +#endif +} // update +// ---------------------------------------------------------------------------- void ModelViewWidget::setupRTTScene() { +#ifndef SERVER_ONLY irr_driver->suppressSkyBox(); if (m_rtt_main_node != NULL) m_rtt_main_node->remove(); @@ -297,42 +308,57 @@ void ModelViewWidget::setupRTTScene() m_camera->setFOV(DEGREE_TO_RAD*50.0f); m_camera->updateAbsolutePosition(); -} +#endif +} // setupRTTScene +// ---------------------------------------------------------------------------- void ModelViewWidget::setRotateOff() { m_rotation_mode = ROTATE_OFF; -} +} // setRotateOff + +// ---------------------------------------------------------------------------- void ModelViewWidget::setRotateContinuously(float speed) { m_rotation_mode = ROTATE_CONTINUOUSLY; m_rotation_speed = speed; -} +} // setRotateContinuously + +// ---------------------------------------------------------------------------- void ModelViewWidget::setRotateTo(float targetAngle, float speed) { m_rotation_mode = ROTATE_TO; m_rotation_speed = speed; m_rotation_target = targetAngle; -} +} // setRotateTo +// ---------------------------------------------------------------------------- bool ModelViewWidget::isRotating() { return m_rotation_mode != ROTATE_OFF ? true : false; -} +} // isRotating +// ---------------------------------------------------------------------------- void ModelViewWidget::elementRemoved() { +#ifndef SERVER_ONLY m_render_target = NULL; IconButtonWidget::elementRemoved(); -} +#endif +} // elementRemoved +// ---------------------------------------------------------------------------- void ModelViewWidget::clearRttProvider() { m_render_target = NULL; -} +} // clearRttProvider +// ---------------------------------------------------------------------------- void ModelViewWidget::drawRTTScene(const irr::core::rect& dest_rect) const { +#ifndef SERVER_ONLY if(m_render_target != NULL) m_render_target->draw2DImage(dest_rect, NULL, video::SColor(255, 255, 255, 255), true); -} +#endif +} // drawRTTScene + diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index 43ee23b23..5b72cf7c3 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -182,7 +182,7 @@ void Attachment::set(AttachmentType type, float time, } } m_node->setVisible(true); - +#ifndef SERVER_ONLY irr_driver->applyObjectPassShader(m_node); // Save event about the new attachment @@ -193,6 +193,7 @@ void Attachment::set(AttachmentType type, float time, saveState(buffer); rwm->addEvent(this, buffer); } +#endif } // set // ----------------------------------------------------------------------------- diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index 9c22be6dd..5683b4100 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -76,6 +76,7 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type, m_max_lifespan = -1; // Add the graphical model +#ifndef SERVER_ONLY setNode(irr_driver->addMesh(m_st_model[type], StringUtils::insertValues("flyable_%i", (int)type))); irr_driver->applyObjectPassShader(getNode()); #ifdef DEBUG @@ -83,7 +84,7 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type, debug_name += type; getNode()->setName(debug_name.c_str()); #endif - +#endif } // Flyable // ---------------------------------------------------------------------------- diff --git a/src/items/item.cpp b/src/items/item.cpp index 2586e2d71..2ab9d969e 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -185,6 +185,7 @@ void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh) scene::ISceneNode* node = m_node->getAllNodes()[0]; ((scene::IMeshSceneNode*)node)->setMesh(mesh); +#ifndef SERVER_ONLY if (lowmesh != NULL) { node = m_node->getAllNodes()[1]; @@ -195,6 +196,7 @@ void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh) irr_driver->applyObjectPassShader(m_node->getAllNodes()[0]); World::getWorld()->getTrack()->adjustForFog(m_node); +#endif } // switchTo //----------------------------------------------------------------------------- diff --git a/src/items/rubber_band.cpp b/src/items/rubber_band.cpp index 42e603a2c..e9245584b 100644 --- a/src/items/rubber_band.cpp +++ b/src/items/rubber_band.cpp @@ -68,14 +68,17 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) verts[i].Color = color; } +#ifndef SERVER_ONLY // Color mb->getMaterial().setTexture(0, getUnicolorTexture(video::SColor(255, 255, 255, 255))); // Gloss mb->getMaterial().setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0))); // Colorization mask mb->getMaterial().setTexture(2, getUnicolorTexture(video::SColor(0, 0, 0, 0))); +#endif updatePosition(); m_node = irr_driver->addMesh(m_mesh, "rubberband"); +#ifndef SERVER_ONLY irr_driver->applyObjectPassShader(m_node); if (STKMeshSceneNode *stkm = dynamic_cast(m_node)) stkm->setReloadEachFrame(true); @@ -83,6 +86,7 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) std::string debug_name = m_owner->getIdent()+" (rubber-band)"; m_node->setName(debug_name.c_str()); #endif +#endif } // RubberBand diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index 25b74d590..9aea483c4 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -73,6 +73,7 @@ LocalPlayerController::LocalPlayerController(AbstractKart *kart, // Attach Particle System Track *track = World::getWorld()->getTrack(); +#ifndef SERVER_ONLY if (UserConfigParams::m_weather_effects && track->getSkyParticles() != NULL) { @@ -88,7 +89,7 @@ LocalPlayerController::LocalPlayerController(AbstractKart *kart, // of the heightmap being calculated and kept in memory m_sky_particles_emitter->addHeightMapAffector(track); } - +#endif } // LocalPlayerController //----------------------------------------------------------------------------- @@ -191,6 +192,7 @@ void LocalPlayerController::update(float dt) // look backward when the player requests or // if automatic reverse camera is active +#ifndef SERVER_ONLY Camera *camera = Camera::getCamera(m_camera_index); if (camera->getType() != Camera::CM_TYPE_END) { @@ -217,7 +219,7 @@ void LocalPlayerController::update(float dt) } } } - +#endif if (m_kart->getKartAnimation() && m_sound_schedule == false && m_kart->getAttachment()->getType() != Attachment::ATTACH_TINYTUX) { @@ -299,8 +301,11 @@ void LocalPlayerController::handleZipper(bool play_sound) m_wee_sound->play(); } +#ifndef SERVER_ONLY // Apply the motion blur according to the speed of the kart irr_driver->giveBoost(m_camera_index); +#endif + } // handleZipper //----------------------------------------------------------------------------- diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 0fe705dc4..ce1123080 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -212,7 +212,11 @@ void Kart::init(RaceManager::KartType type) } +#ifdef SERVER_ONLY + bool animations = false; // server never animates +#else bool animations = true; +#endif const int anims = UserConfigParams::m_show_steering_animations; if (anims == ANIMS_NONE) { @@ -333,9 +337,10 @@ void Kart::reset() m_kart_gfx->reset(); m_skidding->reset(); - +#ifndef SERVER_ONLY if (m_collision_particles) m_collision_particles->setCreationRateAbsolute(0.0f); +#endif m_race_position = m_initial_position; m_finished_race = false; @@ -2051,6 +2056,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal) if(m && m->getCollisionReaction() != Material::NORMAL && !getKartAnimation()) { +#ifndef SERVER_ONLY std::string particles = m->getCrashResetParticles(); if (particles.size() > 0) { @@ -2076,7 +2082,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal) "crash-reset properties\n", particles.c_str()); } } - +#endif if (m->getCollisionReaction() == Material::RESCUE) { new RescueAnimation(this); @@ -2542,12 +2548,13 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model) track_manager->getTrack(race_manager->getTrackName()) ->isFogEnabled() ); } - +#ifndef SERVER_ONLY if (!CVS->supportsShadows()) { m_shadow = new Shadow(m_kart_properties.get(), m_node, -m_kart_model->getLowestPoint()); } +#endif World::getWorld()->kartAdded(this, m_node); } // loadData @@ -2857,6 +2864,7 @@ btQuaternion Kart::getVisualRotation() const */ void Kart::setOnScreenText(const wchar_t *text) { +#ifndef SERVER_ONLY BoldFace* bold_face = font_manager->getFont(); core::dimension2d textsize = bold_face->getDimension(text); @@ -2889,6 +2897,7 @@ void Kart::setOnScreenText(const wchar_t *text) // No need to store the reference to the billboard scene node: // It has one reference to the parent, and will get deleted // when the parent is deleted. +#endif } // setOnScreenText // ------------------------------------------------------------------------ diff --git a/src/karts/kart_gfx.cpp b/src/karts/kart_gfx.cpp index e7251593a..b178377b8 100644 --- a/src/karts/kart_gfx.cpp +++ b/src/karts/kart_gfx.cpp @@ -52,6 +52,7 @@ KartGFX::KartGFX(const AbstractKart *kart) scene::ISceneNode *node = m_kart->getNode(); // Create nitro light core::vector3df location(0.0f, 0.5f, -0.5f*length - 0.05f); +#ifndef SERVER_ONLY m_nitro_light = irr_driver->addLight(location, /*force*/ 0.4f, /*radius*/CVS->isGLSL() ? 5.0f : 1.0f, 0.0f, 0.4f, 1.0f, @@ -82,13 +83,16 @@ KartGFX::KartGFX(const AbstractKart *kart) m_skidding_light_2->setVisible(false); m_skidding_light_2->setName( ("skidding emitter 2 (" + m_kart->getIdent() + ")").c_str() ); +#endif +#ifndef SERVER_ONLY if (CVS->isGLSL()) { m_nitro_light->grab(); m_skidding_light_1->grab(); m_skidding_light_2->grab(); } +#endif // Create particle effects Vec3 rear_left(kart->getWheelGraphicsPosition(3).getX(), 0.05f, @@ -131,13 +135,15 @@ KartGFX::~KartGFX() if(m_all_emitters[i]) delete m_all_emitters[i]; } // for i < KGFX_COUNT - + +#ifndef SERVER_ONLY if (CVS->isGLSL()) { m_nitro_light->drop(); m_skidding_light_1->drop(); m_skidding_light_2->drop(); } +#endif } // ~KartGFX @@ -151,6 +157,7 @@ KartGFX::~KartGFX() void KartGFX::addEffect(KartGFXType type, const std::string &file_name, const Vec3 &position, bool important) { +#ifndef SERVER_ONLY if (!UserConfigParams::m_graphical_effects && (!important || m_kart->getType() == RaceManager::KT_AI || m_kart->getType() == RaceManager::KT_SPARE_TIRE)) @@ -196,6 +203,7 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name, m_skid_kind1 = kind; else if (type==KGFX_SKID2L || type==KGFX_SKID2R) m_skid_kind2 = kind; +#endif } // addEffect // ---------------------------------------------------------------------------- @@ -204,6 +212,7 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name, void KartGFX::reset() { m_wheel_toggle = 1; +#ifndef SERVER_ONLY for(unsigned int i=0; iclearParticles(); } } +#endif } // reset // ---------------------------------------------------------------------------- @@ -224,6 +234,7 @@ void KartGFX::setSkidLevel(const unsigned int level) assert(level >= 1); assert(level <= 2); const ParticleKind *pk = level==1 ? m_skid_kind1 : m_skid_kind2; +#ifndef SERVER_ONLY if(m_all_emitters[KGFX_SKID1L]) m_all_emitters[KGFX_SKID1L]->setParticleType(pk); if(m_all_emitters[KGFX_SKID1R]) @@ -232,6 +243,7 @@ void KartGFX::setSkidLevel(const unsigned int level) // set to indicate that the bonus is now available. setCreationRateRelative(KartGFX::KGFX_SKIDL, 0.0f); setCreationRateRelative(KartGFX::KGFX_SKIDR, 0.0f); +#endif } // setSkidLevel // ---------------------------------------------------------------------------- @@ -242,10 +254,12 @@ void KartGFX::setSkidLevel(const unsigned int level) */ void KartGFX::setParticleKind(const KartGFXType type, const ParticleKind *pk) { +#ifndef SERVER_ONLY ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN]; if(!pe) return; pe->setParticleType(pk); +#endif } // setParticleKind // ---------------------------------------------------------------------------- @@ -255,9 +269,11 @@ void KartGFX::setParticleKind(const KartGFXType type, const ParticleKind *pk) */ void KartGFX::setXYZ(const KartGFXType type, const Vec3 &xyz) { +#ifndef SERVER_ONLY ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN]; if(!pe) return; pe->setPosition(xyz); +#endif } // setXYZ // ---------------------------------------------------------------------------- @@ -268,8 +284,10 @@ void KartGFX::setXYZ(const KartGFXType type, const Vec3 &xyz) */ void KartGFX::setCreationRateAbsolute(KartGFXType type, float f) { +#ifndef SERVER_ONLY if(m_all_emitters[type]) m_all_emitters[type]->setCreationRateAbsolute(f); +#endif } // setCreationRateAbsolute // ---------------------------------------------------------------------------- @@ -282,6 +300,7 @@ void KartGFX::setCreationRateAbsolute(KartGFXType type, float f) */ void KartGFX::setCreationRateRelative(KartGFXType type, float f) { +#ifndef SERVER_ONLY if(m_all_emitters[type]) { if(f<0) @@ -289,6 +308,7 @@ void KartGFX::setCreationRateRelative(KartGFXType type, float f) else m_all_emitters[type]->setCreationRateRelative(f); } +#endif } // setCreationRateRelative // ---------------------------------------------------------------------------- @@ -301,8 +321,10 @@ void KartGFX::setCreationRateRelative(KartGFXType type, float f) */ void KartGFX::resizeBox(KartGFXType type, float new_size) { +#ifndef SERVER_ONLY if(m_all_emitters[type]) m_all_emitters[type]->resizeBox(std::max(0.25f, new_size)); +#endif } // resizeBox // ---------------------------------------------------------------------------- @@ -314,6 +336,7 @@ void KartGFX::resizeBox(KartGFXType type, float new_size) */ void KartGFX::updateTerrain(const ParticleKind *pk) { +#ifndef SERVER_ONLY ParticleEmitter *pe = m_all_emitters[KGFX_TERRAIN]; if(!pe) return; @@ -346,6 +369,7 @@ void KartGFX::updateTerrain(const ParticleKind *pk) // m_skidding can be > 2, and speed > maxSpeed (if powerups are used). if(rate>1.0f) rate = 1.0f; pe->setCreationRateRelative(rate); +#endif } // updateTerrain // ---------------------------------------------------------------------------- @@ -370,6 +394,7 @@ void KartGFX::update(float dt) */ void KartGFX::updateNitroGraphics(float nitro_frac) { +#ifndef SERVER_ONLY // Upate particle effects (creation rate, and emitter size // depending on speed) // -------------------------------------------------------- @@ -389,7 +414,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0); m_nitro_light->setVisible(false); } - +#endif } // updateGraphics // ---------------------------------------------------------------------------- @@ -399,14 +424,17 @@ void KartGFX::updateNitroGraphics(float nitro_frac) */ void KartGFX::updateSkidLight(unsigned int level) { +#ifndef SERVER_ONLY m_skidding_light_1->setVisible(level == 1); m_skidding_light_2->setVisible(level > 1); +#endif } // updateSkidLight // ---------------------------------------------------------------------------- void KartGFX::getGFXStatus(int* nitro, bool* zipper, int* skidding, bool* red_skidding) const { +#ifndef SERVER_ONLY int n = 0; bool z = false; int s = 0; @@ -432,13 +460,14 @@ void KartGFX::getGFXStatus(int* nitro, bool* zipper, *zipper = z; *skidding = s; *red_skidding = r; - +#endif } // getGFXStatus // ---------------------------------------------------------------------------- void KartGFX::setGFXFromReplay(int nitro, bool zipper, int skidding, bool red_skidding) { +#ifndef SERVER_ONLY if (nitro > 0) { setCreationRateAbsolute(KartGFX::KGFX_NITRO1, (float)nitro); @@ -492,12 +521,15 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, m_skidding_light_1->setVisible(false); m_skidding_light_2->setVisible(false); } +#endif } // setGFXFromReplay // ---------------------------------------------------------------------------- void KartGFX::setGFXInvisible() { +#ifndef SERVER_ONLY m_nitro_light->setVisible(false); m_skidding_light_1->setVisible(false); m_skidding_light_2->setVisible(false); +#endif } // setGFXInvisible diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index c9e265346..32f54e479 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -357,6 +357,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim irr_driver->getSceneManager()->getRootSceneNode(), irr_driver->getSceneManager() ); +#ifndef SERVER_ONLY node = irr_driver->addAnimatedMesh(m_mesh, "kartmesh", NULL/*parent*/, getRenderInfo()); @@ -365,7 +366,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim node->setAutomaticCulling(scene::EAC_OFF); else node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); - +#endif if (always_animated) { // give a huge LOD distance for the player's kart. the reason is that it should @@ -409,7 +410,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim if(!m_speed_weighted_objects[i].m_node) continue; m_speed_weighted_objects[i].m_node->setParent(lod_node); } - +#ifndef SERVER_ONLY // Enable rim lighting for the kart irr_driver->applyObjectPassShader(lod_node, true); std::vector &lodnodes = lod_node->getAllNodes(); @@ -418,6 +419,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim { irr_driver->applyObjectPassShader(lodnodes[i], true); } +#endif } else { @@ -428,12 +430,13 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim : 0; scene::IMesh* main_frame = m_mesh; +#ifndef SERVER_ONLY if (!CVS->isGLSL()) { main_frame = m_mesh->getMesh(straight_frame); main_frame->setHardwareMappingHint(scene::EHM_STATIC); } - +#endif std::string debug_name; #ifdef DEBUG @@ -510,12 +513,13 @@ bool KartModel::loadModels(const KartProperties &kart_properties) return false; } +#ifndef SERVER_ONLY scene::ISkinnedMesh* sm = dynamic_cast(m_mesh); if (sm) { MeshTools::createSkinnedMeshWithTangents(sm, &MeshTools::isNormalMap); } - +#endif m_mesh->grab(); irr_driver->grabAllTextures(m_mesh); @@ -564,7 +568,7 @@ bool KartModel::loadModels(const KartProperties &kart_properties) // Grab all textures. This is done for the master only, so // the destructor will only free the textures if a master // copy is freed. - +#ifndef SERVER_ONLY scene::ISkinnedMesh* sm = dynamic_cast(obj.m_model); if (sm) @@ -573,7 +577,7 @@ bool KartModel::loadModels(const KartProperties &kart_properties) &MeshTools::isNormalMap); } irr_driver->grabAllTextures(obj.m_model); - +#endif // Update min/max Vec3 obj_min, obj_max; MeshTools::minMax3D(obj.m_model, &obj_min, &obj_max); @@ -614,8 +618,10 @@ bool KartModel::loadModels(const KartProperties &kart_properties) std::string full_wheel = kart_properties.getKartDir()+m_wheel_filename[i]; m_wheel_model[i] = irr_driver->getMesh(full_wheel); +#ifndef SERVER_ONLY m_wheel_model[i] = MeshTools::createMeshWithTangents(m_wheel_model[i], - &MeshTools::isNormalMap); + &MeshTools::isNormalMap); +#endif // Grab all textures. This is done for the master only, so // the destructor will only free the textures if a master // copy is freed. diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index cae3e0c38..099ca110f 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -249,10 +249,12 @@ void KartProperties::load(const std::string &filename, const std::string &node) else m_minimap_icon = NULL; +#ifndef SERVER_ONLY if (m_minimap_icon == NULL) { m_minimap_icon = getUnicolorTexture(m_color); } +#endif // Only load the model if the .kart file has the appropriate version, // otherwise warnings are printed. diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index 233d1e3eb..55aa85953 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -66,6 +66,7 @@ void Moveable::setNode(scene::ISceneNode *n) void Moveable::updateGraphics(float dt, const Vec3& offset_xyz, const btQuaternion& rotation) { +#ifndef SERVER_ONLY Vec3 xyz=getXYZ()+offset_xyz; m_node->setPosition(xyz.toIrrVector()); btQuaternion r_all = getRotation()*rotation; @@ -75,6 +76,7 @@ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz, Vec3 hpr; hpr.setHPR(r_all); m_node->setRotation(hpr.toIrrHPR()); +#endif } // updateGraphics //----------------------------------------------------------------------------- diff --git a/src/main.cpp b/src/main.cpp index 040c37c49..ac1549c60 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,8 +60,8 @@ physics -> audio "translations\n(too many connections\nto draw)" "configuration\n(too many connections\nto draw)" -# addons -> tracks -# addons -> karts + addons -> tracks + addons -> karts guiengine -> addons guiengine -> race addons -> online_manager @@ -222,6 +222,7 @@ #include "replay/replay_play.hpp" #include "replay/replay_recorder.hpp" #include "states_screens/main_menu_screen.hpp" +#include "states_screens/networking_lobby.hpp" #include "states_screens/register_screen.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/user_screen.hpp" @@ -572,8 +573,10 @@ void cmdLineHelp() // " (so n=1 means all Ais will be the test ai)\n" // " " --server=name Start a server (not a playing client).\n" + " --public-server Allow direct connection to the server (without stk server)\n" " --lan-server=name Start a LAN server (not a playing client).\n" " --server-password= Sets a password for a server (both client&server).\n" + " --connect-now=ip Connect to a server with IP known now (in format x.x.x.x:xxx(port)).\n" " --login=s Automatically log in (set the login).\n" " --password=s Automatically log in (set the password).\n" " --port=n Port number to use.\n" @@ -978,6 +981,34 @@ int handleCmdLine() // Networking command lines NetworkConfig::get()-> setMaxPlayers(UserConfigParams::m_server_max_players); + if (CommandLine::has("--port", &n)) + { + // We don't know if this instance is going to be a client + // or server, so just set both ports, only one will be used anyway + NetworkConfig::get()->setClientPort(n); + NetworkConfig::get()->setServerPort(n); + } + if (CommandLine::has("--public-server")) + { + NetworkConfig::get()->setIsPublicServer(); + } + if (CommandLine::has("--connect-now", &s)) + { + TransportAddress ip(s); + TransportAddress me(2130706433/*127.0.0.1*/, + NetworkConfig::get()->getServerDiscoveryPort() ); + NetworkConfig::get()->setIsLAN(); + NetworkConfig::get()->setIsServer(false); + NetworkConfig::get()->setMyAddress(me); + Log::info("main", "Try to connect to server '%s'.", + ip.toString().c_str() ); + irr::core::stringw name = StringUtils::utf8ToWide(ip.toString()); + ServersManager::get()->addServer(new Server(name, /*lan*/true, + 16, 0, ip)); + ServersManager::get()->setJoinedServer(0); + STKHost::create(); + } + if(CommandLine::has("--server", &s)) { NetworkConfig::get()->setServerName(core::stringw(s.c_str())); @@ -1613,6 +1644,7 @@ int main(int argc, char *argv[] ) } Log::warn("OpenGL", "Driver is too old!"); } +#ifndef SERVER_ONLY else if (!CVS->isGLSL()) { if (UserConfigParams::m_old_driver_popup) @@ -1631,7 +1663,7 @@ int main(int argc, char *argv[] ) } Log::warn("OpenGL", "OpenGL version is too old!"); } - +#endif // Note that on the very first run of STK internet status is set to // "not asked", so the report will only be sent in the next run. if(UserConfigParams::m_internet_status==Online::RequestManager::IPERM_ALLOWED) @@ -1639,7 +1671,13 @@ int main(int argc, char *argv[] ) HardwareStats::reportHardwareStats(); } - if(!UserConfigParams::m_no_start_screen) + // This can only be the case if --connect-now was used, which adds + // a server to the server list. + if (ServersManager::get()->getNumServers()==1) + { + NetworkingLobby::getInstance()->push(); + } + else if (!UserConfigParams::m_no_start_screen) { // If there is a current player, it was saved in the config file, // so we immediately start the main menu (unless it was requested @@ -1894,6 +1932,8 @@ void runUnitTests() GraphicsRestrictions::unitTesting(); Log::info("UnitTest", "NetworkString"); NetworkString::unitTesting(); + Log::info("UnitTest", "TransportAddress"); + TransportAddress::unitTesting(); Log::info("UnitTest", "Easter detection"); // Test easter mode: in 2015 Easter is 5th of April - check with 0 days diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index bb6422486..34e1d2eec 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -320,6 +320,7 @@ void SoccerWorld::countdownReachedZero() //----------------------------------------------------------------------------- void SoccerWorld::initKartList() { +#ifndef SERVER_ONLY const unsigned int kart_amount = (unsigned int)m_karts.size(); //Loading the indicator textures @@ -340,13 +341,14 @@ void SoccerWorld::initKartList() float arrow_pos_height = km->getHeight() + 0.5f; SoccerTeam team = getKartTeam(i); - arrow_node = irr_driver->addBillboard(core::dimension2d(0.3f, - 0.3f), team == SOCCER_TEAM_BLUE ? blue : red, m_karts[i] - ->getNode(), true); + arrow_node = irr_driver->addBillboard( + core::dimension2d(0.3f,0.3f), + team == SOCCER_TEAM_BLUE ? blue : red, + m_karts[i]->getNode(), true); arrow_node->setPosition(core::vector3df(0, arrow_pos_height, 0)); } - +#endif } // initKartList //----------------------------------------------------------------------------- diff --git a/src/modes/world.cpp b/src/modes/world.cpp index f7689f8bb..293a060f2 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -224,8 +224,10 @@ void World::init() // Load other custom models if needed loadCustomModels(); +#ifndef SERVER_ONLY // Now that all models are loaded, apply the overrides irr_driver->applyObjectPassShader(); +#endif // Must be called after all karts are created m_race_gui->init(); diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 7dcfa8f54..c60a1c7c4 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -28,6 +28,8 @@ #include "karts/abstract_kart.hpp" #include "modes/world.hpp" #include "network/network_config.hpp" +#include "network/protocols/client_lobby.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/race_event_manager.hpp" #include "tracks/track.hpp" @@ -51,7 +53,6 @@ WorldStatus::WorldStatus() if (device->getTimer()->isStopped()) device->getTimer()->start(); - m_ready_to_race = false; } // WorldStatus //----------------------------------------------------------------------------- @@ -93,9 +94,9 @@ void WorldStatus::reset() // Set the right music World::getWorld()->getTrack()->startMusic(); // In case of a networked race the race can only start once - // all protocols are up. This flag waits for that, and is - // set by - m_ready_to_race = !NetworkConfig::get()->isNetworking(); + // all protocols are up. This flag is used to wait for + // a confirmation before starting the actual race. + m_server_is_ready = false; } // reset //----------------------------------------------------------------------------- @@ -179,10 +180,6 @@ void WorldStatus::update(float dt) */ void WorldStatus::updateTime(const float dt) { - // In case of a networked race wait till all necessary protocols are - // ready before progressing the timer - if (!m_ready_to_race) return; - switch (m_phase) { // Note: setup phase must be a separate phase, since the race_manager @@ -243,35 +240,34 @@ void WorldStatus::updateTime(const float dt) m_prestart_sound->play(); // In a networked game the client needs to wait for a notification - // from the server that ready-set-go can start now. So client will go - // to the 'wait_for_server_phase', from which they will progress once - // the notification is received. In all other cases (no networking or - // server), immediately go to race start - if(!NetworkConfig::get()->isNetworking() || - NetworkConfig::get()->isServer() ) - { - // Notify the clients that they can start ready-set-go - if(NetworkConfig::get()->isServer()) - RaceEventManager::getInstance()->startReadySetGo(); - m_server_is_ready = true; - } // if not networked - m_phase = WAIT_FOR_SERVER_PHASE; + // from the server that all clients and the server are ready to + // start the game. The server will actually wait for all clients + // to confirm that they have started the race before starting + // itself. In a normal race, this phase is skipped and the race + // starts immediately. + m_phase = NetworkConfig::get()->isNetworking() ? WAIT_FOR_SERVER_PHASE + : READY_PHASE; return; // Don't increase time case WAIT_FOR_SERVER_PHASE: - // On a client this phase waits for the server to be ready. On a - // server or in case of non-networked game this phase is reached - // with m_server_is_ready set to true, so it will immediately - // start the engines and then the race - if(!m_server_is_ready) return; + { + // This stage is only reached in case of a networked game. + // A client waits for a message from the server that it can + // start the race (i.e. that all clients and the server have + // loaded the world). The server waits for a confirmation from + // each client that they have started (to guarantee that the + // server is running with a local time behind all clients). + if (!m_server_is_ready) return; - m_phase = READY_PHASE; + m_phase = READY_PHASE; + Protocol *p = LobbyProtocol::get(); + ClientLobby *cl = dynamic_cast(p); + if (cl) + cl->startingRaceNow(); + return; // Don't increase time + } + case READY_PHASE: startEngines(); - // Receiving a 'startReadySetGo' message from the server triggers - // a call to startReadySetGo() here, which will change the phase - // (or state) of the finite state machine. - return; // Don't increase time - case READY_PHASE: if (m_auxiliary_timer > 1.0) { if (m_play_ready_set_go_sounds) @@ -432,8 +428,11 @@ void WorldStatus::updateTime(const float dt) //----------------------------------------------------------------------------- /** Called on the client when it receives a notification from the server that - * the server is now starting its ready-set-go phase. This function changes - * the state of the finite state machine to be ready. + * all clients (and server) are ready to start the race. The server will + * then additionally wait for all clients to report back that they are + * starting, which guarantees that the server is running far enough behind + * clients time that at server time T all events from the clients at time + * T have arrived, minimising rollback impact. */ void WorldStatus::startReadySetGo() { diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp index d94ede6c1..f98fa3a6c 100644 --- a/src/modes/world_status.hpp +++ b/src/modes/world_status.hpp @@ -94,9 +94,6 @@ protected: /** If the start race should be played, disabled in cutscenes. */ bool m_play_racestart_sounds; - /** A flag that causes the world to wait in case of a networking race - * till all protocols are up and running. */ - bool m_ready_to_race; private: /** Sound to play at the beginning of a race, during which a * a camera intro of the track can be shown. */ @@ -130,10 +127,10 @@ private: bool m_engines_started; void startEngines(); - /** In networked game the client must wait for the server to start 'ready set go' - * (to guarantee that the client's time is not ahead of the server), This flag - * indicates that the notification from the server was received, and that the - * client can go to 'ready' phase. */ + /** In networked game a client must wait for the server to start 'ready + * set go' to make sure all client are actually ready to start the game. + * A server on the other hand will run behind all clients, so it will + * wait for all clients to indicate that they have started the race. */ bool m_server_is_ready; public: @@ -198,7 +195,7 @@ public: /** Get the time since start regardless of which way the clock counts */ float getTimeSinceStart() const { return m_count_up_timer; } // ------------------------------------------------------------------------ - void setReadyToRace() { m_ready_to_race = true; } + void setReadyToRace() { m_server_is_ready = true; } }; // WorldStatus diff --git a/src/network/network_config.cpp b/src/network/network_config.cpp index 83e8111d8..efa329b48 100644 --- a/src/network/network_config.cpp +++ b/src/network/network_config.cpp @@ -37,6 +37,7 @@ NetworkConfig::NetworkConfig() { m_network_type = NETWORK_NONE; m_is_server = false; + m_is_public_server = false; m_max_players = 4; m_is_registered = false; m_server_name = ""; diff --git a/src/network/network_config.hpp b/src/network/network_config.hpp index 935a373d2..b7ce8d726 100644 --- a/src/network/network_config.hpp +++ b/src/network/network_config.hpp @@ -34,11 +34,18 @@ private: static NetworkConfig *m_network_config; enum NetworkType - { NETWORK_NONE, NETWORK_WAN, NETWORK_LAN }; + { + NETWORK_NONE, NETWORK_WAN, NETWORK_LAN + }; /** Keeps the type of network connection: none (yet), LAN or WAN. */ NetworkType m_network_type; + /** If set it allows clients to connect directly to this server without + * using the stk server in between. It requires obviously that this + * server is accessible (through the firewall) from the outside. */ + bool m_is_public_server; + /** True if this host is a server, false otherwise. */ bool m_is_server; @@ -79,7 +86,7 @@ public: /** Singleton get, which creates this object if necessary. */ static NetworkConfig *get() { - if(!m_network_config) + if (!m_network_config) m_network_config = new NetworkConfig(); return m_network_config; } // get @@ -102,19 +109,19 @@ public: } // setServerDiscoveryPort // ------------------------------------------------------------------------ /** Sets the port on which this server listens. */ - void setServerPort(uint16_t port) { m_server_port = port; } + void setServerPort(uint16_t port) { m_server_port = port; } // ------------------------------------------------------------------------ /** Sets the port on which a client listens for server connection. */ - void setClientPort(uint16_t port) { m_client_port = port; } + void setClientPort(uint16_t port) { m_client_port = port; } // ------------------------------------------------------------------------ /** Returns the port on which this server listenes. */ - uint16_t getServerPort() const { return m_server_port; } + uint16_t getServerPort() const { return m_server_port; } // ------------------------------------------------------------------------ /** Returns the port for LAN server discovery. */ uint16_t getServerDiscoveryPort() const { return m_server_discovery_port; } // ------------------------------------------------------------------------ /** Returns the port on which a client listens for server connections. */ - uint16_t getClientPort() const { return m_client_port; } + uint16_t getClientPort() const { return m_client_port; } // ------------------------------------------------------------------------ /** Sets the password for a server. */ void setPassword(const std::string &password) { m_password = password; } @@ -122,6 +129,12 @@ public: /** Returns the password. */ const std::string& getPassword() const { return m_password; } // ------------------------------------------------------------------------ + /** Sets that this server can be contacted directly. */ + void setIsPublicServer() { m_is_public_server = true; } + // ------------------------------------------------------------------------ + /** Returns if connections directly to the server are to be accepted. */ + bool isPublicServer() const { return m_is_public_server; } + // ------------------------------------------------------------------------ /** Return if a network setting is happening. A network setting is active * if a host (server or client) exists. */ bool isNetworking() const { return m_network_type!=NETWORK_NONE; } diff --git a/src/network/network_console.cpp b/src/network/network_console.cpp index b83729ec3..9f673ed81 100644 --- a/src/network/network_console.cpp +++ b/src/network/network_console.cpp @@ -21,10 +21,9 @@ #include "main_loop.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -#include "network/protocol_manager.hpp" #include "network/stk_host.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" -#include "network/protocols/server_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/protocols/stop_server.hpp" #include "network/stk_peer.hpp" #include "utils/log.hpp" @@ -79,27 +78,23 @@ void* NetworkConsole::mainLoop(void* data) } else if (str == "start" && NetworkConfig::get()->isServer()) { - ServerLobbyRoomProtocol* protocol = - static_cast - (ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); - assert(protocol); - protocol->startGame(); + ServerLobby* protocol = + dynamic_cast(LobbyProtocol::get()); + protocol->signalRaceStartToClients(); } else if (str == "selection" && NetworkConfig::get()->isServer()) { - ServerLobbyRoomProtocol* protocol = - static_cast - (ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); - assert(protocol); + ServerLobby* protocol = + dynamic_cast(LobbyProtocol::get()); protocol->startSelection(); } else if (str == "select" && NetworkConfig::get()->isClient()) { std::string str2; getline(std::cin, str2); - Protocol* protocol = - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM); - ClientLobbyRoomProtocol* clrp = static_cast(protocol); + ServerLobby* protocol = + dynamic_cast(LobbyProtocol::get()); + ClientLobby* clrp = dynamic_cast(protocol); std::vector players = STKHost::get()->getMyPlayerProfiles(); // For now send a vote for each local player @@ -114,10 +109,9 @@ void* NetworkConsole::mainLoop(void* data) std::cout << "Vote for ? (track/laps/reversed/major/minor/race#) :"; std::string str2; getline(std::cin, str2); - Protocol* protocol = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_LOBBY_ROOM); - ClientLobbyRoomProtocol* clrp = - static_cast(protocol); + LobbyProtocol* protocol = LobbyProtocol::get(); + ClientLobby* clrp = + dynamic_cast(protocol); std::vector players = STKHost::get()->getMyPlayerProfiles(); if (str2 == "track") diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index 1aaff34d6..269633c4f 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -118,8 +118,7 @@ void Protocol::findAndTerminateProtocol(ProtocolType type) if (protocol) protocol->requestTerminate(); else - Log::error("ClientLobbyRoomProtocol", - "No protocol %d registered.", type); + Log::error("Protocol", "No protocol %d registered.", type); } // findAndTerminateProtocol // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby.cpp similarity index 77% rename from src/network/protocols/client_lobby_room_protocol.cpp rename to src/network/protocols/client_lobby.cpp index d8d06e406..8941a449b 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -16,15 +16,15 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" #include "config/player_manager.hpp" #include "modes/world_with_rank.hpp" #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -#include "network/protocols/start_game_protocol.hpp" #include "network/protocol_manager.hpp" +#include "network/protocols/latency_protocol.hpp" #include "network/race_event_manager.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" @@ -35,26 +35,52 @@ #include "states_screens/state_manager.hpp" #include "utils/log.hpp" -ClientLobbyRoomProtocol:: -ClientLobbyRoomProtocol(const TransportAddress& server_address) - : LobbyRoomProtocol(NULL) +// ============================================================================ +/** The protocol that manages starting a race with the server. It uses a + * finite state machine: +\dot +digraph interaction { +"NONE" -> "LINKED" [label="ENet connection with server established"] +"LINKED" -> "REQUESTING_CONNECTION" [label="Request connection from server"] +"REQUESTING_CONNECTION" -> CONNECTED [label="Connection accepted by server"] +"REQUESTING_CONNECTION" -> "?? TO BE DONE ??" [label="Connection refused by server"] +"CONNECTED" -> "KART_SELECTION" [label="Server tells us to start kart selection"] +"KART_SELECTION" -> "SELECTING_KARTS" [label="Show kart selection screen"] +"SELECTING_KARTS" -> "PLAYING" [label="Server sends start race message"] +} +\enddot +Note that some states are actually managed outside of the client lobby. For +example to select race details after selecting a kart is managed by the GUI +engine. + +*/ + +ClientLobby::ClientLobby() : LobbyProtocol(NULL) { - m_server_address.copy(server_address); + + m_server_address.clear(); m_server = NULL; setHandleDisconnections(true); -} // ClientLobbyRoomProtocol +} // ClientLobby //----------------------------------------------------------------------------- -ClientLobbyRoomProtocol::~ClientLobbyRoomProtocol() +ClientLobby::~ClientLobby() { -} // ClientLobbyRoomProtocol +} // ClientLobby //----------------------------------------------------------------------------- - -void ClientLobbyRoomProtocol::setup() +/** Sets the address of the server. + */ +void ClientLobby::setAddress(const TransportAddress &address) { - m_setup = STKHost::get()->setupNewGame(); // create a new setup + m_server_address.copy(address); +} // setAddress +//----------------------------------------------------------------------------- + +void ClientLobby::setup() +{ + m_game_setup = STKHost::get()->setupNewGame(); // create a new game setup m_state = NONE; } // setup @@ -63,8 +89,8 @@ void ClientLobbyRoomProtocol::setup() * \param player_id The global player id of the voting player. * \param kart_name Name of the selected kart. */ -void ClientLobbyRoomProtocol::requestKartSelection(uint8_t player_id, - const std::string &kart_name) +void ClientLobby::requestKartSelection(uint8_t player_id, + const std::string &kart_name) { NetworkString *request = getNetworkString(3+kart_name.size()); request->addUInt8(LE_KART_SELECTION).addUInt8(player_id) @@ -80,7 +106,7 @@ void ClientLobbyRoomProtocol::requestKartSelection(uint8_t player_id, * \param player_id The global player id of the voting player. * \param major Major mode voted for. */ -void ClientLobbyRoomProtocol::voteMajor(uint8_t player_id, uint32_t major) +void ClientLobby::voteMajor(uint8_t player_id, uint32_t major) { NetworkString *request = getNetworkString(6); request->addUInt8(LE_VOTE_MAJOR).addUInt8(player_id) @@ -96,7 +122,7 @@ void ClientLobbyRoomProtocol::voteMajor(uint8_t player_id, uint32_t major) * \param player_id The global player id of the voting player. * \param count NUmber of tracks to play. */ -void ClientLobbyRoomProtocol::voteRaceCount(uint8_t player_id, uint8_t count) +void ClientLobby::voteRaceCount(uint8_t player_id, uint8_t count) { NetworkString *request = getNetworkString(3); request->addUInt8(LE_VOTE_RACE_COUNT).addUInt8(player_id).addUInt8(count); @@ -111,7 +137,7 @@ void ClientLobbyRoomProtocol::voteRaceCount(uint8_t player_id, uint8_t count) * \param player_id The global player id of the voting player. * \param minor Voted minor mode. */ -void ClientLobbyRoomProtocol::voteMinor(uint8_t player_id, uint32_t minor) +void ClientLobby::voteMinor(uint8_t player_id, uint32_t minor) { NetworkString *request = getNetworkString(6); request->addUInt8(LE_VOTE_MINOR).addUInt8(player_id).addUInt32(minor); @@ -127,7 +153,7 @@ void ClientLobbyRoomProtocol::voteMinor(uint8_t player_id, uint32_t minor) * \param track Name of the track. * \param At which place in the list of tracks this track should be played. */ -void ClientLobbyRoomProtocol::voteTrack(uint8_t player_id, +void ClientLobby::voteTrack(uint8_t player_id, const std::string &track, uint8_t track_nb) { @@ -147,7 +173,7 @@ void ClientLobbyRoomProtocol::voteTrack(uint8_t player_id, * \param track_nb Index for the track to be voted on in the list of all * tracks. */ -void ClientLobbyRoomProtocol::voteReversed(uint8_t player_id, bool reversed, +void ClientLobby::voteReversed(uint8_t player_id, bool reversed, uint8_t track_nb) { NetworkString *request = getNetworkString(9); @@ -164,7 +190,7 @@ void ClientLobbyRoomProtocol::voteReversed(uint8_t player_id, bool reversed, * \param laps Number of laps for the specified track. * \param track_nb Index of the track in the list of all tracks. */ -void ClientLobbyRoomProtocol::voteLaps(uint8_t player_id, uint8_t laps, +void ClientLobby::voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb) { NetworkString *request = getNetworkString(10); @@ -177,7 +203,7 @@ void ClientLobbyRoomProtocol::voteLaps(uint8_t player_id, uint8_t laps, //----------------------------------------------------------------------------- /** Called when a client selects to exit a server. */ -void ClientLobbyRoomProtocol::leave() +void ClientLobby::leave() { m_server->disconnect(); STKHost::get()->removePeer(m_server); @@ -190,7 +216,7 @@ void ClientLobbyRoomProtocol::leave() * screen. It notifies the server that this client has exited the screen and * is back at the lobby. */ -void ClientLobbyRoomProtocol::doneWithResults() +void ClientLobby::doneWithResults() { NetworkString *done = getNetworkString(1); done->addUInt8(LE_RACE_FINISHED_ACK); @@ -200,18 +226,19 @@ void ClientLobbyRoomProtocol::doneWithResults() //----------------------------------------------------------------------------- -bool ClientLobbyRoomProtocol::notifyEvent(Event* event) +bool ClientLobby::notifyEvent(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists NetworkString &data = event->data(); assert(data.size()); // assert that data isn't empty uint8_t message_type = data.getUInt8(); - Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d", + Log::info("ClientLobby", "Synchronous message of type %d", message_type); switch(message_type) { case LE_KART_SELECTION_UPDATE: kartSelectionUpdate(event); break; + case LE_LOAD_WORLD: loadWorld(); break; case LE_RACE_FINISHED: raceFinished(event); break; case LE_EXIT_RESULT: exitResultScreen(event); break; default: @@ -223,16 +250,16 @@ bool ClientLobbyRoomProtocol::notifyEvent(Event* event) //----------------------------------------------------------------------------- -bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event) +bool ClientLobby::notifyEventAsynchronous(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists if (event->getType() == EVENT_TYPE_MESSAGE) { NetworkString &data = event->data(); assert(data.size()); // assert that data isn't empty uint8_t message_type = data.getUInt8(); - Log::info("ClientLobbyRoomProtocol", "Asynchronous message of type %d", + Log::info("ClientLobby", "Asynchronous message of type %d", message_type); switch(message_type) { @@ -269,7 +296,7 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event) //----------------------------------------------------------------------------- -void ClientLobbyRoomProtocol::update(float dt) +void ClientLobby::update(float dt) { switch (m_state) { @@ -309,6 +336,10 @@ void ClientLobbyRoomProtocol::update(float dt) NetworkKartSelectionScreen::getInstance(); screen->push(); m_state = SELECTING_KARTS; + + Protocol *p = new LatencyProtocol(); + p->requestStart(); + Log::info("LobbyProtocol", "LatencyProtocol started."); } break; case SELECTING_KARTS: @@ -338,7 +369,7 @@ void ClientLobbyRoomProtocol::update(float dt) * Data | player_id | hostid | player name | * ------------------------------------- */ -void ClientLobbyRoomProtocol::newPlayer(Event* event) +void ClientLobby::newPlayer(Event* event) { if (!checkDataSize(event, 2)) return; const NetworkString &data = event->data(); @@ -350,21 +381,21 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) // FIXME need adjusting when splitscreen is used/ if(STKHost::get()->getGameSetup()->isLocalMaster(player_id)) { - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "The server notified me that I'm a new player in the " "room (not normal)."); } - else if (m_setup->getProfile(player_id) == NULL) + else if (m_game_setup->getProfile(player_id) == NULL) { - Log::verbose("ClientLobbyRoomProtocol", "New player connected."); + Log::verbose("ClientLobby", "New player connected."); NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, player_id, host_id); - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); } else { - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "One of the player notified in the list is myself."); } } // newPlayer @@ -381,7 +412,7 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) * Data | player id *| * -------------- */ -void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) +void ClientLobby::disconnectedPlayer(Event* event) { if (!checkDataSize(event, 1)) return; @@ -389,16 +420,16 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) while(data.size()>0) { const NetworkPlayerProfile *profile = - m_setup->getProfile(data.getUInt8()); - if (m_setup->removePlayer(profile)) + m_game_setup->getProfile(data.getUInt8()); + if (m_game_setup->removePlayer(profile)) { - Log::info("ClientLobbyRoomProtocol", + Log::info("ClientLobby", "Player %d removed successfully.", profile->getGlobalPlayerId()); } else { - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "The disconnected peer wasn't known."); } } // while @@ -418,7 +449,7 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) * Data | player_id| hostid | authorised |playernames* | * --------------------------------------------------------- */ -void ClientLobbyRoomProtocol::connectionAccepted(Event* event) +void ClientLobby::connectionAccepted(Event* event) { // At least 3 bytes should remain now if(!checkDataSize(event, 3)) return; @@ -428,7 +459,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) // Accepted // ======== - Log::info("ClientLobbyRoomProtocol", + Log::info("ClientLobby", "The server accepted the connection."); // self profile @@ -448,7 +479,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, my_player_id, my_host_id); STKHost::get()->getGameSetup()->setLocalMaster(my_player_id); - m_setup->setNumLocalPlayers(1); + m_game_setup->setNumLocalPlayers(1); // connection token uint32_t token = data.getToken(); peer->setClientServerToken(token); @@ -464,7 +495,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) NetworkPlayerProfile* profile2 = new NetworkPlayerProfile(name, player_id, host_id); - m_setup->addPlayer(profile2); + m_game_setup->addPlayer(profile2); // Inform the network lobby of all players so that the GUI can // show all currently connected players. NetworkingLobby::getInstance()->addPlayer(profile2); @@ -472,7 +503,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) // Add self after other players so that player order is identical // on server and all clients. - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); m_server = event->getPeer(); m_state = CONNECTED; @@ -490,7 +521,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) * Data | refusal code | * ---------------- */ -void ClientLobbyRoomProtocol::connectionRefused(Event* event) +void ClientLobby::connectionRefused(Event* event) { if (!checkDataSize(event, 1)) return; const NetworkString &data = event->data(); @@ -498,17 +529,17 @@ void ClientLobbyRoomProtocol::connectionRefused(Event* event) switch (data.getUInt8()) // the second byte { case 0: - Log::info("ClientLobbyRoomProtocol", + Log::info("ClientLobby", "Connection refused : too many players."); break; case 1: - Log::info("ClientLobbyRoomProtocol", "Connection refused : banned."); + Log::info("ClientLobby", "Connection refused : banned."); break; case 2: - Log::info("ClientLobbyRoomProtocol", "Client busy."); + Log::info("ClientLobby", "Client busy."); break; default: - Log::info("ClientLobbyRoomProtocol", "Connection refused."); + Log::info("ClientLobby", "Connection refused."); break; } } // connectionRefused @@ -525,7 +556,7 @@ void ClientLobbyRoomProtocol::connectionRefused(Event* event) * Data | refusal code | * ---------------- */ -void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event) +void ClientLobby::kartSelectionRefused(Event* event) { if(!checkDataSize(event, 1)) return; @@ -534,15 +565,15 @@ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event) switch (data.getUInt8()) // the error code { case 0: - Log::info("ClientLobbyRoomProtocol", + Log::info("ClientLobby", "Kart selection refused : already taken."); break; case 1: - Log::info("ClientLobbyRoomProtocol", + Log::info("ClientLobby", "Kart selection refused : not available."); break; default: - Log::info("ClientLobbyRoomProtocol", "Kart selection refused."); + Log::info("ClientLobby", "Kart selection refused."); break; } } // kartSelectionRefused @@ -559,48 +590,64 @@ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event) * Data | player id | N (kart name size) | kart name | * -------------------------------------------------- */ -void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event) +void ClientLobby::kartSelectionUpdate(Event* event) { if(!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); std::string kart_name; data.decodeString(&kart_name); - if (!m_setup->isKartAvailable(kart_name)) + if (!m_game_setup->isKartAvailable(kart_name)) { - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "The updated kart is taken already."); } - m_setup->setPlayerKart(player_id, kart_name); + m_game_setup->setPlayerKart(player_id, kart_name); NetworkKartSelectionScreen::getInstance()->playerSelected(player_id, kart_name); } // kartSelectionUpdate //----------------------------------------------------------------------------- -/*! \brief Called when the race needs to be started. +/*! \brief Called when the server broadcasts to start the race. +race needs to be started. * \param event : Event providing the information (no additional information * in this case). */ -void ClientLobbyRoomProtocol::startGame(Event* event) +void ClientLobby::startGame(Event* event) { - const NetworkString &data = event->data(); m_state = PLAYING; - ProtocolManager::getInstance() - ->requestStart(new StartGameProtocol(m_setup)); - Log::info("ClientLobbyRoomProtocol", "Starting new game"); + // Triggers the world finite state machine to go from WAIT_FOR_SERVER_PHASE + // to READY_PHASE. + World::getWorld()->setReadyToRace(); + Log::info("ClientLobby", "Starting new game"); } // startGame //----------------------------------------------------------------------------- +/** Called from WorldStatus when reaching the READY phase, i.e. when the race + * was started. It is going to inform the server of the race start. This + * allows the server to wait for all clients to start, so the server will + * be running behind the client with the biggest latency, which should + * make it likely that at local time T on the server all messages from + * all clients at their local time T have arrived. + */ +void ClientLobby::startingRaceNow() +{ + NetworkString *ns = getNetworkString(2); + ns->addUInt8(LE_STARTED_RACE); + sendToServer(ns, /*reliable*/true); + terminateLatencyProtocol(); +} // startingRaceNow +//----------------------------------------------------------------------------- /*! \brief Called when the kart selection starts. * \param event : Event providing the information (no additional information * in this case). */ -void ClientLobbyRoomProtocol::startSelection(Event* event) +void ClientLobby::startSelection(Event* event) { m_state = KART_SELECTION; - Log::info("ClientLobbyRoomProtocol", "Kart selection starts now"); + Log::info("ClientLobby", "Kart selection starts now"); } // startSelection //----------------------------------------------------------------------------- @@ -615,12 +662,12 @@ void ClientLobbyRoomProtocol::startSelection(Event* event) * Data | Kart 1 ID | kart id 2 | ... | * ------------------------------- */ -void ClientLobbyRoomProtocol::raceFinished(Event* event) +void ClientLobby::raceFinished(Event* event) { if(!checkDataSize(event, 1)) return; NetworkString &data = event->data(); - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "Server notified that the race is finished."); // stop race protocols @@ -629,7 +676,7 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "No controller events protocol registered."); protocol = ProtocolManager::getInstance() @@ -637,7 +684,7 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "No kart update protocol registered."); protocol = ProtocolManager::getInstance() @@ -645,7 +692,7 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) if (protocol) ProtocolManager::getInstance()->requestTerminate(protocol); else - Log::error("ClientLobbyRoomProtocol", + Log::error("ClientLobby", "No game events protocol registered."); // finish the race @@ -657,7 +704,7 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) { uint8_t kart_id = data.getUInt8(); ranked_world->setKartPosition(kart_id,position); - Log::info("ClientLobbyRoomProtocol", "Kart %d has finished #%d", + Log::info("ClientLobby", "Kart %d has finished #%d", kart_id, position); position++; } @@ -670,7 +717,7 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event) /** Called when the server informs the clients to exit the race result screen. * It exits the race, and goes back to the lobby. */ -void ClientLobbyRoomProtocol::exitResultScreen(Event *event) +void ClientLobby::exitResultScreen(Event *event) { RaceResultGUI::getInstance()->backToLobby(); } // exitResultScreen @@ -686,14 +733,14 @@ void ClientLobbyRoomProtocol::exitResultScreen(Event *event) * Data |player id | major mode vote | * ------------------------------ */ -void ClientLobbyRoomProtocol::playerMajorVote(Event* event) +void ClientLobby::playerMajorVote(Event* event) { const NetworkString &data = event->data(); if (!checkDataSize(event, 2)) return; uint8_t player_id = data.getUInt8(); uint8_t mode = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerMajorVote(player_id, mode); + m_game_setup->getRaceConfig()->setPlayerMajorVote(player_id, mode); } // playerMajorVote //----------------------------------------------------------------------------- @@ -707,13 +754,13 @@ void ClientLobbyRoomProtocol::playerMajorVote(Event* event) * Data | player id | races count | * --------------------------- */ -void ClientLobbyRoomProtocol::playerRaceCountVote(Event* event) +void ClientLobby::playerRaceCountVote(Event* event) { if (!checkDataSize(event, 2)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t count = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, count); + m_game_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, count); } // playerRaceCountVote //----------------------------------------------------------------------------- @@ -727,13 +774,13 @@ void ClientLobbyRoomProtocol::playerRaceCountVote(Event* event) * Data | player id | minor mode vote | * ------------------------------- */ -void ClientLobbyRoomProtocol::playerMinorVote(Event* event) +void ClientLobby::playerMinorVote(Event* event) { if (!checkDataSize(event, 2)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t minor = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); + m_game_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); } // playerMinorVote //----------------------------------------------------------------------------- @@ -748,7 +795,7 @@ void ClientLobbyRoomProtocol::playerMinorVote(Event* event) * Data | player id | track number (gp) | N | track name | * -------------------------------------------------- */ -void ClientLobbyRoomProtocol::playerTrackVote(Event* event) +void ClientLobby::playerTrackVote(Event* event) { if (!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); @@ -756,7 +803,7 @@ void ClientLobbyRoomProtocol::playerTrackVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t number = data.getUInt8(); int N = data.decodeString(&track_name); - m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, + m_game_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, number); } // playerTrackVote @@ -772,14 +819,14 @@ void ClientLobbyRoomProtocol::playerTrackVote(Event* event) * Data | player id |reversed | track number (gp) | * ------------------------------------------- */ -void ClientLobbyRoomProtocol::playerReversedVote(Event* event) +void ClientLobby::playerReversedVote(Event* event) { if (!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t reversed = data.getUInt8(); uint8_t number = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerReversedVote(player_id, reversed!=0, + m_game_setup->getRaceConfig()->setPlayerReversedVote(player_id, reversed!=0, number); } // playerReversedVote @@ -792,17 +839,39 @@ void ClientLobbyRoomProtocol::playerReversedVote(Event* event) * Byte 0 1 2 * ---------------------------------------- * Size | 1 | 1 | 1 | - * Data | player id | laps | track number (gp) | + * Data | player id | laps | track number (gp) | * ---------------------------------------- */ -void ClientLobbyRoomProtocol::playerLapsVote(Event* event) +void ClientLobby::playerLapsVote(Event* event) { if (!checkDataSize(event, 3)) return; const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t laps = data.getUInt8(); uint8_t number = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerLapsVote(player_id, laps, number); + m_game_setup->getRaceConfig()->setPlayerLapsVote(player_id, laps, number); } // playerLapsVote //----------------------------------------------------------------------------- +/** Callback when the world is loaded. The client will inform the server + * that the players on this host are ready to start the race. It is called by + * the RaceManager after the world is loaded. + */ +void ClientLobby::finishedLoadingWorld() +{ + assert(STKHost::get()->getPeerCount() == 1); + std::vector players = + STKHost::get()->getMyPlayerProfiles(); + NetworkString *ns = getNetworkString(2); + ns->addUInt8(LE_CLIENT_LOADED_WORLD); + ns->addUInt8( uint8_t(players.size()) ) ; + for (unsigned int i = 0; i < players.size(); i++) + { + ns->addUInt8(players[i]->getGlobalPlayerId()); + Log::info("ClientLobby", + "Player %d ready, notifying server.", + players[i]->getGlobalPlayerId()); + } // for i < players.size() + sendToServer(ns, /*reliable*/true); + delete ns; +} // finishedLoadingWorld diff --git a/src/network/protocols/client_lobby_room_protocol.hpp b/src/network/protocols/client_lobby.hpp similarity index 81% rename from src/network/protocols/client_lobby_room_protocol.hpp rename to src/network/protocols/client_lobby.hpp index 1e0547473..39edbd131 100644 --- a/src/network/protocols/client_lobby_room_protocol.hpp +++ b/src/network/protocols/client_lobby.hpp @@ -1,13 +1,13 @@ -#ifndef CLIENT_LOBBY_ROOM_PROTOCOL_HPP -#define CLIENT_LOBBY_ROOM_PROTOCOL_HPP +#ifndef CLIENT_LOBBY_HPP +#define CLIENT_LOBBY_HPP -#include "network/protocols/lobby_room_protocol.hpp" +#include "network/protocols/lobby_protocol.hpp" #include "network/transport_address.hpp" #include "utils/cpp2011.hpp" class STKPeer; -class ClientLobbyRoomProtocol : public LobbyRoomProtocol +class ClientLobby : public LobbyProtocol { private: void newPlayer(Event* event); @@ -50,11 +50,12 @@ private: STATE m_state; public: - ClientLobbyRoomProtocol(const TransportAddress& server_address); - virtual ~ClientLobbyRoomProtocol(); + ClientLobby(); + virtual ~ClientLobby(); - void requestKartSelection(uint8_t player_id, - const std::string &kart_name); + virtual void requestKartSelection(uint8_t player_id, + const std::string &kart_name) OVERRIDE; + void setAddress(const TransportAddress &address); void voteMajor(uint8_t player_id, uint32_t major); void voteRaceCount(uint8_t player_id, uint8_t count); void voteMinor(uint8_t player_id, uint32_t minor); @@ -63,14 +64,16 @@ public: void voteReversed(uint8_t player_id, bool reversed, uint8_t track_nb = 0); void voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb = 0); void doneWithResults(); + void startingRaceNow(); void leave(); virtual bool notifyEvent(Event* event) OVERRIDE; virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void finishedLoadingWorld() OVERRIDE; virtual void setup() OVERRIDE; virtual void update(float dt) OVERRIDE; virtual void asynchronousUpdate() OVERRIDE {} }; -#endif // CLIENT_LOBBY_ROOM_PROTOCOL_HPP +#endif // CLIENT_LOBBY_HPP diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index 5f4729440..5095d7ed1 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -26,7 +26,7 @@ #include "network/protocols/hide_public_address.hpp" #include "network/protocols/request_connection.hpp" #include "network/protocols/ping_protocol.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" #include "network/protocol_manager.hpp" #include "network/servers_manager.hpp" #include "network/stk_host.hpp" @@ -238,7 +238,9 @@ void ConnectToServer::asynchronousUpdate() // lobby room protocol if we're connected only if(STKHost::get()->getPeers()[0]->isConnected()) { - Protocol *p = new ClientLobbyRoomProtocol(m_server_address); + ClientLobby *p = + LobbyProtocol::create(); + p->setAddress(m_server_address); p->requestStart(); } } diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 66f520981..8daaf3864 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -39,7 +39,7 @@ GameEventsProtocol::~GameEventsProtocol() */ void GameEventsProtocol::setup() { - World::getWorld()->setReadyToRace(); + m_count_ready_clients = 0; } // setup // ---------------------------------------------------------------------------- @@ -63,16 +63,16 @@ bool GameEventsProtocol::notifyEvent(Event* event) int8_t type = data.getUInt8(); switch (type) { - case GE_ITEM_COLLECTED: - collectedItem(data); break; - case GE_KART_FINISHED_RACE: - kartFinishedRace(data); break; - case GE_START_READY_SET_GO: - receivedReadySetGo(); break; + case GE_CLIENT_STARTED_RSG: + receivedClientHasStarted(event); break; + case GE_ITEM_COLLECTED: + collectedItem(data); break; + case GE_KART_FINISHED_RACE: + kartFinishedRace(data); break; - default: - Log::warn("GameEventsProtocol", "Unkown message type."); - break; + default: + Log::warn("GameEventsProtocol", "Unkown message type."); + break; } return true; } // notifyEvent @@ -164,26 +164,37 @@ void GameEventsProtocol::kartFinishedRace(const NetworkString &ns) } // kartFinishedRace // ---------------------------------------------------------------------------- -/** This function is called on a server when the world starts the ready-set-go - * phase. It signals to all clients to do the same. +/** Called on a client when it has started its ready-set-go. The client will + * inform the server anout this. The server will wait for all clients to + * have started before it will start its own countdown. */ -void GameEventsProtocol::startReadySetGo() -{ - assert(NetworkConfig::get()->isServer()); - NetworkString *ns = getNetworkString(1); - ns->setSynchronous(true); - ns->addUInt8(GE_START_READY_SET_GO); - sendMessageToPeersChangingToken(ns, /*reliable*/true); - delete ns; -} // startReadySetGo - -// ---------------------------------------------------------------------------- -/** Called on the client when it receives the message that the server has - * started its ready-set-go. Signal to world that it can go to the next - * phase (ready phase) now. - */ -void GameEventsProtocol::receivedReadySetGo() +void GameEventsProtocol::clientHasStarted() { assert(NetworkConfig::get()->isClient()); - World::getWorld()->startReadySetGo(); -} // receivedReadySetGo + NetworkString *ns = getNetworkString(1); + ns->setSynchronous(true); + ns->addUInt8(GE_CLIENT_STARTED_RSG); + sendToServer(ns, /*reliable*/true); + delete ns; +} // clientHasStarted +// ---------------------------------------------------------------------------- +/** Called on the server when a client has signaled that it has started ready +* set go. The server waits for the last client before it starts its own +* ready set go. */ +void GameEventsProtocol::receivedClientHasStarted(Event *event) +{ + assert(NetworkConfig::get()->isServer()); + m_count_ready_clients++; + Log::verbose("GameEvent", + "Host %d has started ready-set-go: %d out of %d done", + event->getPeer()->getHostId(), m_count_ready_clients, + STKHost::get()->getGameSetup()->getPlayerCount() ); + if (m_count_ready_clients==STKHost::get()->getGameSetup()->getPlayerCount()) + { + Log::verbose("GameEvent", "All %d clients have started.", + STKHost::get()->getGameSetup()->getPlayerCount()); + // SIgnal the server to start now - since it is now behind the client + // times by the latency of the 'slowest' client. + World::getWorld()->startReadySetGo(); + } +} // receivedClientHasStarted diff --git a/src/network/protocols/game_events_protocol.hpp b/src/network/protocols/game_events_protocol.hpp index f793d3228..250108be5 100644 --- a/src/network/protocols/game_events_protocol.hpp +++ b/src/network/protocols/game_events_protocol.hpp @@ -11,11 +11,18 @@ class GameEventsProtocol : public Protocol { private: enum GameEventType { - GE_START_READY_SET_GO = 0x01, + GE_CLIENT_STARTED_RSG = 0x01, GE_ITEM_COLLECTED = 0x02, GE_KART_FINISHED_RACE = 0x03 }; // GameEventType + /** Count how many clients have started 'ready'. The server + * will only go to its 'ready' phase if all client shave done so. + * This means the server time is far enough behind the clients + * that at time T all client messages for time T have been + * received (short of latency spikes). */ + int m_count_ready_clients; + public: GameEventsProtocol(); virtual ~GameEventsProtocol(); @@ -24,9 +31,9 @@ public: void collectedItem(Item* item, AbstractKart* kart); void collectedItem(const NetworkString &ns); void kartFinishedRace(AbstractKart *kart, float time); + void clientHasStarted(); + void receivedClientHasStarted(Event *event); void kartFinishedRace(const NetworkString &ns); - void startReadySetGo(); - void receivedReadySetGo(); virtual void setup() OVERRIDE; virtual void update(float dt) OVERRIDE {}; virtual void asynchronousUpdate() OVERRIDE{} diff --git a/src/network/protocols/latency_protocol.cpp b/src/network/protocols/latency_protocol.cpp new file mode 100644 index 000000000..cffae92f2 --- /dev/null +++ b/src/network/protocols/latency_protocol.cpp @@ -0,0 +1,140 @@ +#include "network/protocols/latency_protocol.hpp" + +#include "network/event.hpp" +#include "network/network_config.hpp" +#include "network/stk_host.hpp" +#include "network/stk_peer.hpp" +#include "utils/time.hpp" + +//----------------------------------------------------------------------------- +/** This protocol tries to determine the average latency between client and + * server. While this information is not used atm, it might be useful for + * the server to determine how much behind the clients it should start. + * FIXME: ATM the main thread will load the world as part of an update + * of the ProtocolManager (which updates the protocols). Since all protocols + * are locked dusing this update, the synchronisation protocol is actually + * delayed from starting while world is loading (since finding the protocol + * for a message requires the protocol lock) - causing at least two frames + * of significanlty delayed pings :( + */ +LatencyProtocol::LatencyProtocol() + : Protocol(PROTOCOL_SYNCHRONIZATION) +{ + unsigned int size = STKHost::get()->getPeerCount(); + m_pings.resize(size, std::map()); + m_successed_pings.resize(size, 0); + m_total_diff.resize(size, 0); + m_average_ping.resize(size, 0); + m_pings_count = 0; +} // LatencyProtocol + +//----------------------------------------------------------------------------- +LatencyProtocol::~LatencyProtocol() +{ +} // ~LatencyProtocol + +//----------------------------------------------------------------------------- +void LatencyProtocol::setup() +{ + Log::info("LatencyProtocol", "Ready !"); +} // setup + + //----------------------------------------------------------------------------- +/** Called when receiving a message. On the client side the message is a ping + * from the server, which is answered back. On the server the received message + * is a reply to a previous ping request. The server will keep track of + * average latency. + */ +bool LatencyProtocol::notifyEventAsynchronous(Event* event) +{ + if (event->getType() != EVENT_TYPE_MESSAGE) + return true; + if(!checkDataSize(event, 5)) return true; + + const NetworkString &data = event->data(); + uint32_t request = data.getUInt8(); + uint32_t sequence = data.getUInt32(); + + const std::vector &peers = STKHost::get()->getPeers(); + assert(peers.size() > 0); + + // Find the right peer id. The host id (i.e. each host sendings its + // host id) can not be used here, since host ids can have gaps (if a + // host should disconnect) + uint8_t peer_id = -1; + for (unsigned int i = 0; i < peers.size(); i++) + { + if (peers[i]->isSamePeer(event->getPeer())) + { + peer_id = i; + break; + } + } + + if (request) + { + // Only a client should receive a request for a ping response + assert(NetworkConfig::get()->isClient()); + NetworkString *response = getNetworkString(5); + // The '0' indicates a response to a ping request + response->addUInt8(0).addUInt32(sequence); + event->getPeer()->sendPacket(response, false); + delete response; + } + else // receive response to a ping request + { + // Only a server should receive this kind of message + assert(NetworkConfig::get()->isServer()); + if (sequence >= m_pings[peer_id].size()) + { + Log::warn("LatencyProtocol", + "The sequence# %u isn't known.", sequence); + return true; + } + double current_time = StkTime::getRealTime(); + m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence]; + m_successed_pings[peer_id]++; + m_average_ping[peer_id] = + (int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0); + + Log::debug("LatencyProtocol", + "Peer %d sequence %d ping %u average %u at %lf", + peer_id, sequence, + (unsigned int)((current_time - m_pings[peer_id][sequence])*1000), + m_average_ping[peer_id], + StkTime::getRealTime()); + } + return true; +} // notifyEventAsynchronous + +//----------------------------------------------------------------------------- +/** Waits for the countdown to be started. On the server the start of the + * countdown is triggered by ServerLobby::finishedLoadingWorld(), + * which is called once all clients have confirmed that they are ready to + * start. The server will send a ping request to each client once a second, + * and include the information if the countdown has started (and its current + * value). On the client the countdown is started in notifyEvenAsynchronous() + * when a server ping is received that indicates that the countdown has + * started. The measured times can be used later to estimate the latency + * between server and client. + */ +void LatencyProtocol::asynchronousUpdate() +{ + float current_time = float(StkTime::getRealTime()); + if (NetworkConfig::get()->isServer() && current_time > m_last_time+1) + { + const std::vector &peers = STKHost::get()->getPeers(); + for (unsigned int i = 0; i < peers.size(); i++) + { + NetworkString *ping_request = + getNetworkString(5); + ping_request->addUInt8(1).addUInt32(m_pings[i].size()); + m_pings[i] [ m_pings_count ] = current_time; + peers[i]->sendPacket(ping_request, false); + delete ping_request; + } // for i M peers + m_last_time = current_time; + m_pings_count++; + } // if current_time > m_last_time + 0.1 +} // asynchronousUpdate + diff --git a/src/network/protocols/latency_protocol.hpp b/src/network/protocols/latency_protocol.hpp new file mode 100644 index 000000000..1ef1ded7c --- /dev/null +++ b/src/network/protocols/latency_protocol.hpp @@ -0,0 +1,38 @@ +#ifndef LATENCY_PROTOCOL_HPP +#define LATENCY_PROTOCOL_HPP + +#include "network/protocol.hpp" +#include "utils/cpp2011.hpp" + +#include +#include + +class LatencyProtocol : public Protocol +{ +private: + std::vector > m_pings; + std::vector m_average_ping; + + /** Counts the number of pings sent. */ + uint32_t m_pings_count; + std::vector m_successed_pings; + std::vector m_total_diff; + + /** Keeps track of last time that an update was sent. */ + double m_last_time; + + +public: + LatencyProtocol(); + virtual ~LatencyProtocol(); + + virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void setup() OVERRIDE; + virtual void asynchronousUpdate() OVERRIDE; + + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE {} + +}; // class LatencyProtocol + +#endif // LATENCY_PROTOCOL_HPP diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp new file mode 100644 index 000000000..d6c3cc5f8 --- /dev/null +++ b/src/network/protocols/lobby_protocol.cpp @@ -0,0 +1,143 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#include "network/protocols/lobby_protocol.hpp" + +#include "input/input_manager.hpp" +#include "input/device_manager.hpp" +#include "modes/world.hpp" +#include "network/network_player_profile.hpp" +#include "network/protocol_manager.hpp" +#include "network/protocols/controller_events_protocol.hpp" +#include "network/protocols/game_events_protocol.hpp" +#include "network/protocols/kart_update_protocol.hpp" +#include "network/protocols/latency_protocol.hpp" +#include "network/race_event_manager.hpp" +#include "network/stk_host.hpp" +#include "race/race_manager.hpp" +#include "states_screens/state_manager.hpp" + +LobbyProtocol *LobbyProtocol::m_lobby = NULL; + +LobbyProtocol::LobbyProtocol(CallbackObject* callback_object) + : Protocol(PROTOCOL_LOBBY_ROOM, callback_object) +{ + m_game_setup = NULL; +} // LobbyProtocol + +// ---------------------------------------------------------------------------- +LobbyProtocol::~LobbyProtocol() +{ +} // ~LobbyProtocol + +//----------------------------------------------------------------------------- +/** Starts the sychronization protocol and the RaceEventManager. It then + * sets the player structures up, creates the active player, and loads + * the world. + * This is called on the client when the server informs them that + * the world can be loaded (LE_LOAD_WORLD) and on the server in state + * LOAD_WORLD (i.e. just after informing all clients). + */ +void LobbyProtocol::loadWorld() +{ + Log::info("LobbyProtocol", "Ready !"); + + // Race startup sequence + // --------------------- + // This creates the network world. + RaceEventManager::getInstance()->start(); + + // The number of karts includes the AI karts, which are not supported atm + race_manager->setNumKarts(m_game_setup->getPlayerCount()); + + // Set number of global and local players. + race_manager->setNumPlayers(m_game_setup->getPlayerCount(), + m_game_setup->getNumLocalPlayers()); + + // Create the kart information for the race manager: + // ------------------------------------------------- + std::vector players = m_game_setup->getPlayers(); + int local_player_id = 0; + for (unsigned int i = 0; i < players.size(); i++) + { + NetworkPlayerProfile* profile = players[i]; + bool is_local = profile->isLocalPlayer(); + + // All non-local players are created here. This means all players + // on the server, and all non-local players on a client (the local + // karts are created in the NetworkingLobby). + if (!is_local) + { + // On the server no device or player profile is needed. + StateManager::get()->createActivePlayer(NULL, NULL); + } + + // Adjust the local player id so that local players have the numbers + // 0 to num-1; and all other karts start with num. This way the local + // players get the first ActivePlayers assigned (which have the + // corresponding device associated with it). + RemoteKartInfo rki(is_local ? local_player_id + : i - local_player_id + + STKHost::get()->getGameSetup()->getNumLocalPlayers(), + profile->getKartName(), + profile->getName(), + profile->getHostId(), + !is_local); + rki.setGlobalPlayerId(profile->getGlobalPlayerId()); + rki.setPerPlayerDifficulty(profile->getPerPlayerDifficulty()); + if (is_local) + { + rki.setLocalPlayerId(local_player_id); + local_player_id++; + } + + // Inform the race manager about the data for this kart. + race_manager->setPlayerKart(i, rki); + } // for i in players + + // Make sure that if there is only a single local player this player can + // use all input devices. + StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1 + ? NULL + : StateManager::get()->getActivePlayer(0); + + input_manager->getDeviceManager()->setSinglePlayer(ap); + + Log::info("LobbyProtocol", "Player configuration ready."); + + // Load the actual world. + m_game_setup->getRaceConfig()->loadWorld(); + World::getWorld()->setNetworkWorld(true); + (new KartUpdateProtocol())->requestStart(); + (new ControllerEventsProtocol())->requestStart(); + (new GameEventsProtocol())->requestStart(); + +} // loadWorld + +// ---------------------------------------------------------------------------- +/** Terminates the LatencyProtocol. + */ +void LobbyProtocol::terminateLatencyProtocol() +{ + Protocol *p = ProtocolManager::getInstance() + ->getProtocol(PROTOCOL_SYNCHRONIZATION); + LatencyProtocol *sp = dynamic_cast(p); + if (sp) + sp->requestTerminate(); +} // stopLatencyProtocol diff --git a/src/network/protocols/lobby_room_protocol.hpp b/src/network/protocols/lobby_protocol.hpp similarity index 65% rename from src/network/protocols/lobby_room_protocol.hpp rename to src/network/protocols/lobby_protocol.hpp index 9fa9185e3..8b00cbb7f 100644 --- a/src/network/protocols/lobby_room_protocol.hpp +++ b/src/network/protocols/lobby_protocol.hpp @@ -16,8 +16,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 LOBBY_ROOM_PROTOCOL_HPP -#define LOBBY_ROOM_PROTOCOL_HPP +#ifndef LOBBY_PROTOCOL_HPP +#define LOBBY_PROTOCOL_HPP #include "network/protocol.hpp" @@ -25,12 +25,12 @@ #include "network/network_string.hpp" /*! - * \class LobbyRoomProtocol + * \class LobbyProtocol * \brief Base class for both client and server lobby. The lobbies are started * when a server opens a game, or when a client joins a game. * It is used to exchange data about the race settings, like kart selection. */ -class LobbyRoomProtocol : public Protocol +class LobbyProtocol : public Protocol { public: /** Lists all lobby events (LE). */ @@ -45,11 +45,15 @@ public: LE_NEW_PLAYER_CONNECTED, // inform client about new player LE_KART_SELECTION, // Player selected kart LE_PLAYER_DISCONNECTED, // Client disconnected - LE_START_RACE, // start race + LE_CLIENT_LOADED_WORLD, // Client finished loading world + LE_LOAD_WORLD, // Clients should load world + LE_START_RACE, // Server to client to start race + LE_STARTED_RACE, // Client to server that it has started race LE_START_SELECTION, // inform client to start selection LE_RACE_FINISHED, // race has finished, display result LE_RACE_FINISHED_ACK, // client went back to lobby LE_EXIT_RESULT, // Force clients to exit race result screen + LE_VOTE, // Any vote (race mode, track, ...) LE_VOTE_MAJOR, // vote of major race mode LE_VOTE_MINOR, // vote for minor race mode LE_VOTE_RACE_COUNT, // vote for number of tracks @@ -59,21 +63,45 @@ public: }; protected: + static LobbyProtocol *m_lobby; + /** The game setup. */ - GameSetup* m_setup; + GameSetup* m_game_setup; public: - LobbyRoomProtocol(CallbackObject* callback_object) - : Protocol(PROTOCOL_LOBBY_ROOM, callback_object) - { - m_setup = NULL; - } // LobbyRoomProtocol - // ------------------------------------------------------------------------ - virtual ~LobbyRoomProtocol() {} - // ------------------------------------------------------------------------ - virtual void setup() = 0; - virtual void update(float dt) = 0; -}; // class LobbyRoomProtocol -#endif // LOBBY_ROOM_PROTOCOL_HPP + /** Creates either a client or server lobby protocol as a singleton. */ + template static S* create() + { + assert(m_lobby == NULL); + m_lobby = new S(); + return dynamic_cast(m_lobby); + } // create + + // ------------------------------------------------------------------------ + /** Returns the singleton client or server lobby protocol. */ + static LobbyProtocol *get() + { + assert(m_lobby); + return m_lobby; + } // get + + // ------------------------------------------------------------------------ + + LobbyProtocol(CallbackObject* callback_object); + virtual ~LobbyProtocol(); + virtual void setup() = 0; + virtual void update(float dt) = 0; + virtual void finishedLoadingWorld() = 0; + virtual void loadWorld(); + void terminateLatencyProtocol(); + virtual void requestKartSelection(uint8_t player_id, + const std::string &kart_name) + { + assert(false); // Only defined in client + }; + +}; // class LobbyProtocol + +#endif // LOBBY_PROTOCOL_HPP diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby.cpp similarity index 69% rename from src/network/protocols/server_lobby_room_protocol.cpp rename to src/network/protocols/server_lobby.cpp index f17279476..144ba5e5b 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -16,7 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "network/protocols/server_lobby_room_protocol.hpp" +#include "network/protocols/server_lobby.hpp" #include "config/player_manager.hpp" #include "config/user_config.hpp" @@ -26,7 +26,7 @@ #include "network/network_player_profile.hpp" #include "network/protocols/get_public_address.hpp" #include "network/protocols/connect_to_peer.hpp" -#include "network/protocols/start_game_protocol.hpp" +#include "network/protocols/latency_protocol.hpp" #include "network/protocol_manager.hpp" #include "network/race_event_manager.hpp" #include "network/stk_host.hpp" @@ -41,57 +41,107 @@ #include "utils/time.hpp" -/** This is the central game setup protocol running in the server. +/** This is the central game setup protocol running in the server. It is + * mostly a finite state machine. Note that all nodes in ellipses and light + * grey background are actual states; nodes in boxes and white background + * are functions triggered from a state or triggering potentially a state + * change. + \dot + digraph interaction { + node [shape=box]; "Server Constructor"; "playerTrackVote"; "connectionRequested"; + "signalRaceStartToClients"; "startedRaceOnClient"; "loadWorld"; + node [shape=ellipse,style=filled,color=lightgrey]; + + "Server Constructor" -> "INIT_WAN" [label="If WAN game"] + "Server Constructor" -> "ACCEPTING_CLIENTS" [label="If LAN game"] + "INIT_WAN" -> "GETTING_PUBLIC_ADDRESS" [label="GetPublicAddress protocol callback"] + "GETTING_PUBLIC_ADDRESS" -> "ACCEPTING_CLIENTS" [label="Register server"] + "ACCEPTING_CLIENTS" -> "connectionRequested" [label="Client connection request"] + "connectionRequested" -> "ACCEPTING_CLIENTS" + "ACCEPTING_CLIENTS" -> "SELECTING" [label="Start race from authorised client"] + "SELECTING" -> "SELECTING" [label="Client selects kart, #laps, ..."] + "SELECTING" -> "playerTrackVote" [label="Client selected track"] + "playerTrackVote" -> "SELECTING" [label="Not all clients have selected"] + "playerTrackVote" -> "LOAD_WORLD" [label="All clients have selected; signal load_world to clients"] + "LOAD_WORLD" -> "loadWorld" + "loadWorld" -> "WAIT_FOR_WORLD_LOADED" + "WAIT_FOR_WORLD_LOADED" -> "WAIT_FOR_WORLD_LOADED" [label="Client or server loaded world"] + "WAIT_FOR_WORLD_LOADED" -> "signalRaceStartToClients" [label="All clients and server ready"] + "signalRaceStartToClients" -> "WAIT_FOR_RACE_STARTED" + "WAIT_FOR_RACE_STARTED" -> "startedRaceOnClient" [label="Client has started race"] + "startedRaceOnClient" -> "WAIT_FOR_RACE_STARTED" [label="Not all clients have started"] + "startedRaceOnClient" -> "DELAY_SERVER" [label="All clients have started"] + "DELAY_SERVER" -> "DELAY_SERVER" [label="Not done waiting"] + "DELAY_SERVER" -> "RACING" [label="Server starts race now"] + } + \enddot + + * It starts with detecting the public ip address and port of this * host (GetPublicAddress). */ -ServerLobbyRoomProtocol::ServerLobbyRoomProtocol() : LobbyRoomProtocol(NULL) +ServerLobby::ServerLobby() : LobbyProtocol(NULL) { setHandleDisconnections(true); -} // ServerLobbyRoomProtocol +} // ServerLobby //----------------------------------------------------------------------------- /** Destructor. */ -ServerLobbyRoomProtocol::~ServerLobbyRoomProtocol() +ServerLobby::~ServerLobby() { -} // ~ServerLobbyRoomProtocol +} // ~ServerLobby //----------------------------------------------------------------------------- -void ServerLobbyRoomProtocol::setup() +void ServerLobby::setup() { - m_setup = STKHost::get()->setupNewGame(); - m_setup->setNumLocalPlayers(0); // no local players on a server + m_game_setup = STKHost::get()->setupNewGame(); + m_game_setup->setNumLocalPlayers(0); // no local players on a server m_next_player_id.setAtomic(0); // In case of LAN we don't need our public address or register with the // STK server, so we can directly go to the accepting clients state. m_state = NetworkConfig::get()->isLAN() ? ACCEPTING_CLIENTS - : NONE; + : INIT_WAN; m_selection_enabled = false; m_current_protocol = NULL; - Log::info("ServerLobbyRoomProtocol", "Starting the protocol."); + Log::info("ServerLobby", "Starting the protocol."); + + // Initialise the data structures to detect if all clients and + // the server are ready: + m_player_states.clear(); + m_client_ready_count.setAtomic(0); + m_server_has_loaded_world = false; + const std::vector &players = + m_game_setup->getPlayers(); + for (unsigned int i = 0; i < players.size(); i++) + { + m_player_states[players[i]->getGlobalPlayerId()] = false; + } + } // setup //----------------------------------------------------------------------------- -bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) +bool ServerLobby::notifyEventAsynchronous(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists if (event->getType() == EVENT_TYPE_MESSAGE) { NetworkString &data = event->data(); assert(data.size()); // message not empty uint8_t message_type; message_type = data.getUInt8(); - Log::info("ServerLobbyRoomProtocol", "Message received with type %d.", + Log::info("ServerLobby", "Message received with type %d.", message_type); switch(message_type) { case LE_CONNECTION_REQUESTED: connectionRequested(event); break; case LE_REQUEST_BEGIN: startSelection(event); break; case LE_KART_SELECTION: kartSelectionRequested(event); break; + case LE_CLIENT_LOADED_WORLD: finishedLoadingWorldClient(event); break; + case LE_STARTED_RACE: startedRaceOnClient(event); break; case LE_VOTE_MAJOR: playerMajorVote(event); break; case LE_VOTE_RACE_COUNT: playerRaceCountVote(event); break; case LE_VOTE_MINOR: playerMinorVote(event); break; @@ -114,11 +164,11 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) * is known, register the server and its address with the stk server so that * client can find it. */ -void ServerLobbyRoomProtocol::update(float dt) +void ServerLobby::update(float dt) { switch (m_state) { - case NONE: + case INIT_WAN: // Start the protocol to find the public ip address. m_current_protocol = new GetPublicAddress(this); m_current_protocol->requestStart(); @@ -127,19 +177,19 @@ void ServerLobbyRoomProtocol::update(float dt) requestPause(); break; case GETTING_PUBLIC_ADDRESS: - { - Log::debug("ServerLobbyRoomProtocol", "Public address known."); - // Free GetPublicAddress protocol - delete m_current_protocol; + { + Log::debug("ServerLobby", "Public address known."); + // Free GetPublicAddress protocol + delete m_current_protocol; - // Register this server with the STK server. This will block - // this thread, but there is no need for the protocol manager - // to react to any requests before the server is registered. - registerServer(); - Log::info("ServerLobbyRoomProtocol", "Server registered."); - m_state = ACCEPTING_CLIENTS; - } - break; + // Register this server with the STK server. This will block + // this thread, but there is no need for the protocol manager + // to react to any requests before the server is registered. + registerServer(); + Log::info("ServerLobby", "Server registered."); + m_state = ACCEPTING_CLIENTS; + } + break; case ACCEPTING_CLIENTS: { // Only poll the STK server if this is a WAN server. @@ -148,7 +198,42 @@ void ServerLobbyRoomProtocol::update(float dt) break; } case SELECTING: - break; // Nothing to do, this is event based + // The function playerTrackVote will trigger the next state + // once all track votes have been received. + break; + case LOAD_WORLD: + Log::info("ServerLobbyRoom", "Starting the race loading."); + // This will create the world instance, i.e. load track and karts + loadWorld(); + m_state = WAIT_FOR_WORLD_LOADED; + break; + case WAIT_FOR_WORLD_LOADED: + // Note that m_server_has_loaded_world is called by the main thread + // (same a the thread updating this protocol) + m_client_ready_count.lock(); + if (m_server_has_loaded_world && + m_client_ready_count.getData() == m_game_setup->getPlayerCount()) + { + signalRaceStartToClients(); + m_server_delay = 0.02f; + m_client_ready_count.getData() = 0; + } + m_client_ready_count.unlock(); + // Initialise counter again, to wait for all clients to indicate that + // they have started the race/ + break; + case WAIT_FOR_RACE_STARTED: + // The function finishedLoadingWorldClient() will trigger the + // next state. + break; + case DELAY_SERVER: + m_server_delay -= dt; + if (m_server_delay < 0) + { + m_state = RACING; + World::getWorld()->setReadyToRace(); + } + break; case RACING: if (World::getWorld() && RaceEventManager::getInstance()->isRunning()) @@ -190,7 +275,7 @@ void ServerLobbyRoomProtocol::update(float dt) /** Callback when the GetPublicAddress terminates. It will unpause this * protocol, which triggers the next state of the finite state machine. */ -void ServerLobbyRoomProtocol::callback(Protocol *protocol) +void ServerLobby::callback(Protocol *protocol) { requestUnpause(); } // callback @@ -202,7 +287,7 @@ void ServerLobbyRoomProtocol::callback(Protocol *protocol) * ProtocolManager thread). The information about this client is added * to the table 'server'. */ -void ServerLobbyRoomProtocol::registerServer() +void ServerLobby::registerServer() { Online::XMLRequest *request = new Online::XMLRequest(); const TransportAddress& addr = NetworkConfig::get()->getMyAddress(); @@ -236,27 +321,33 @@ void ServerLobbyRoomProtocol::registerServer() } // registerServer //----------------------------------------------------------------------------- -/** This function informs each client to start the race, and then starts the - * StartGameProtocol. +/** This function is called when all clients have loaded the world and + * are therefore ready to start the race. It signals to all clients + * to start the race and then switches state to DELAY_SERVER. */ -void ServerLobbyRoomProtocol::startGame() +void ServerLobby::signalRaceStartToClients() { const std::vector &peers = STKHost::get()->getPeers(); NetworkString *ns = getNetworkString(1); ns->addUInt8(LE_START_RACE); sendMessageToPeersChangingToken(ns, /*reliable*/true); delete ns; - Protocol *p = new StartGameProtocol(m_setup); - p->requestStart(); - m_state = RACING; + m_state = WAIT_FOR_RACE_STARTED; } // startGame //----------------------------------------------------------------------------- /** Instructs all clients to start the kart selection. If event is not NULL, * the command comes from a client (which needs to be authorised). */ -void ServerLobbyRoomProtocol::startSelection(const Event *event) +void ServerLobby::startSelection(const Event *event) { + + if (m_state != ACCEPTING_CLIENTS) + { + Log::warn("ServerLobby", + "Received startSelection while being in state %d", m_state); + return; + } if(event && !event->getPeer()->isAuthorised()) { Log::warn("ServerLobby", @@ -275,13 +366,18 @@ void ServerLobbyRoomProtocol::startSelection(const Event *event) m_state = SELECTING; WaitingForOthersScreen::getInstance()->push(); + + Protocol *p = new LatencyProtocol(); + p->requestStart(); + Log::info("LobbyProtocol", "LatencyProtocol started."); + } // startSelection //----------------------------------------------------------------------------- /** Query the STK server for connection requests. For each connection request * start a ConnectToPeer protocol. */ -void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() +void ServerLobby::checkIncomingConnectionRequests() { // First poll every 5 seconds. Return if no polling needs to be done. const float POLL_INTERVAL = 5.0f; @@ -307,7 +403,7 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() if (!result->get("success", &success) || success != "yes") { - Log::error("ServerLobbyRoomProtocol", "Cannot retrieve the list."); + Log::error("ServerLobby", "Cannot retrieve the list."); return; } @@ -317,7 +413,7 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() for (unsigned int i = 0; i < users_xml->getNumNodes(); i++) { users_xml->getNode(i)->get("id", &id); - Log::debug("ServerLobbyRoomProtocol", + Log::debug("ServerLobby", "User with id %d wants to connect.", id); Protocol *p = new ConnectToPeer(id); p->requestStart(); @@ -330,7 +426,7 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() * to state RESULT_DISPLAY, during which the race result gui is shown and all * clients can click on 'continue'. */ - void ServerLobbyRoomProtocol::checkRaceFinished() + void ServerLobby::checkRaceFinished() { assert(RaceEventManager::getInstance()->isRunning()); assert(World::getWorld()); @@ -368,12 +464,12 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() for (unsigned int i = 0; i < karts_results.size(); i++) { total->addUInt8(karts_results[i]); // kart pos = i+1 - Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d", + Log::info("ServerLobby", "Kart %d finished #%d", karts_results[i], i + 1); } sendMessageToPeersChangingToken(total, /*reliable*/ true); delete total; - Log::info("ServerLobbyRoomProtocol", "End of game message sent"); + Log::info("ServerLobby", "End of game message sent"); } // checkRaceFinished @@ -381,7 +477,7 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests() /** Called when a client disconnects. * \param event The disconnect event. */ -void ServerLobbyRoomProtocol::clientDisconnected(Event* event) +void ServerLobby::clientDisconnected(Event* event) { std::vector players_on_host = event->getPeer()->getAllPlayerProfiles(); @@ -392,9 +488,9 @@ void ServerLobbyRoomProtocol::clientDisconnected(Event* event) for(unsigned int i=0; iaddUInt8(players_on_host[i]->getGlobalPlayerId()); - Log::info("ServerLobbyRoomProtocol", "Player disconnected : id %d", + Log::info("ServerLobby", "Player disconnected : id %d", players_on_host[i]->getGlobalPlayerId()); - m_setup->removePlayer(players_on_host[i]); + m_game_setup->removePlayer(players_on_host[i]); } sendMessageToPeersChangingToken(msg, /*reliable*/true); @@ -416,13 +512,13 @@ void ServerLobbyRoomProtocol::clientDisconnected(Event* event) * Data | 4 |n| player name | * --------------------- */ -void ServerLobbyRoomProtocol::connectionRequested(Event* event) +void ServerLobby::connectionRequested(Event* event) { STKPeer* peer = event->getPeer(); const NetworkString &data = event->data(); // can we add the player ? - if (m_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() || + if (m_game_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() || m_state!=ACCEPTING_CLIENTS ) { NetworkString *message = getNetworkString(2); @@ -433,7 +529,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) // send only to the peer that made the request peer->sendPacket(message); delete message; - Log::verbose("ServerLobbyRoomProtocol", "Player refused"); + Log::verbose("ServerLobby", "Player refused"); return; } @@ -451,8 +547,8 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) m_next_player_id.getData()++; int new_player_id = m_next_player_id.getData(); m_next_player_id.unlock(); - if(m_setup->getLocalMasterID()==0) - m_setup->setLocalMaster(new_player_id); + if(m_game_setup->getLocalMasterID()==0) + m_game_setup->setLocalMaster(new_player_id); // The host id has already been incremented when the peer // was added, so it is the right id now. @@ -480,7 +576,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) peer->setAuthorised(is_authorised); peer->setHostId(new_host_id); - const std::vector &players = m_setup->getPlayers(); + const std::vector &players = m_game_setup->getPlayers(); // send a message to the one that asked to connect // Estimate 10 as average name length NetworkString *message_ack = getNetworkString(4 + players.size() * (2+10)); @@ -500,10 +596,10 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, new_player_id, new_host_id); - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); - Log::verbose("ServerLobbyRoomProtocol", "New player."); + Log::verbose("ServerLobby", "New player."); } // connectionRequested @@ -519,7 +615,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) * Data |player id | N (kart name size) | kart name | * ---------------------------------------------- */ -void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) +void ServerLobby::kartSelectionRequested(Event* event) { if(m_state!=SELECTING) { @@ -547,7 +643,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) return; } // check if somebody picked that kart - if (!m_setup->isKartAvailable(kart_name)) + if (!m_game_setup->isKartAvailable(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is already taken @@ -557,7 +653,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) return; } // check if this kart is authorized - if (!m_setup->isKartAllowed(kart_name)) + if (!m_game_setup->isKartAllowed(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is not authorized @@ -576,7 +672,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) .encodeString(kart_name); sendMessageToPeersChangingToken(answer); delete answer; - m_setup->setPlayerKart(player_id, kart_name); + m_game_setup->setPlayerKart(player_id, kart_name); } // kartSelectionRequested //----------------------------------------------------------------------------- @@ -591,14 +687,14 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) * Data | player-id | major mode vote | * ------------------------------- */ -void ServerLobbyRoomProtocol::playerMajorVote(Event* event) +void ServerLobby::playerMajorVote(Event* event) { if (!checkDataSize(event, 5)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint32_t major = data.getUInt32(); - m_setup->getRaceConfig()->setPlayerMajorVote(player_id, major); + m_game_setup->getRaceConfig()->setPlayerMajorVote(player_id, major); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(6); other->addUInt8(LE_VOTE_MAJOR).addUInt8(player_id).addUInt32(major); @@ -617,13 +713,13 @@ void ServerLobbyRoomProtocol::playerMajorVote(Event* event) * Data | player-id | races count | * --------------------------- */ -void ServerLobbyRoomProtocol::playerRaceCountVote(Event* event) +void ServerLobby::playerRaceCountVote(Event* event) { if (!checkDataSize(event, 1)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t race_count = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, race_count); + m_game_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, race_count); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3); other->addUInt8(LE_VOTE_RACE_COUNT).addUInt8(player_id) @@ -644,13 +740,13 @@ void ServerLobbyRoomProtocol::playerRaceCountVote(Event* event) * Data | player-id | minor mode vote | * ------------------------------- */ -void ServerLobbyRoomProtocol::playerMinorVote(Event* event) +void ServerLobby::playerMinorVote(Event* event) { if (!checkDataSize(event, 1)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint32_t minor = data.getUInt32(); - m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); + m_game_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3); @@ -671,7 +767,7 @@ void ServerLobbyRoomProtocol::playerMinorVote(Event* event) * Data | player id | track number (gp) | N | track name | * -------------------------------------------------- */ -void ServerLobbyRoomProtocol::playerTrackVote(Event* event) +void ServerLobby::playerTrackVote(Event* event) { if (!checkDataSize(event, 3)) return; NetworkString &data = event->data(); @@ -681,7 +777,7 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) uint8_t track_number = data.getUInt8(); std::string track_name; int N = data.decodeString(&track_name); - m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, + m_game_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, track_number); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3+1+data.size()); @@ -689,8 +785,19 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) .encodeString(track_name); sendMessageToPeersChangingToken(other); delete other; - if(m_setup->getRaceConfig()->getNumTrackVotes()==m_setup->getPlayerCount()) - startGame(); + + // Check if we received all information + if (m_game_setup->getRaceConfig()->getNumTrackVotes() == + m_game_setup->getPlayerCount()) + { + // Inform clients to start loading the world + NetworkString *ns = getNetworkString(1); + ns->setSynchronous(true); + ns->addUInt8(LE_LOAD_WORLD); + sendMessageToPeersChangingToken(ns, /*reliable*/true); + delete ns; + m_state = LOAD_WORLD; // Server can now load world + } } // playerTrackVote //----------------------------------------------------------------------------- @@ -704,7 +811,7 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) * Data | player id | reversed | track number (gp) | * -------------------------------------------- */ -void ServerLobbyRoomProtocol::playerReversedVote(Event* event) +void ServerLobby::playerReversedVote(Event* event) { if (!checkDataSize(event, 3)) return; @@ -712,8 +819,8 @@ void ServerLobbyRoomProtocol::playerReversedVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t reverse = data.getUInt8(); uint8_t nb_track = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerReversedVote(player_id, - reverse!=0, nb_track); + m_game_setup->getRaceConfig()->setPlayerReversedVote(player_id, + reverse!=0, nb_track); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_REVERSE).addUInt8(player_id).addUInt8(reverse) @@ -733,15 +840,15 @@ void ServerLobbyRoomProtocol::playerReversedVote(Event* event) * Data | player id | laps | track number (gp) | * ---------------------------------------- */ -void ServerLobbyRoomProtocol::playerLapsVote(Event* event) +void ServerLobby::playerLapsVote(Event* event) { if (!checkDataSize(event, 2)) return; NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t lap_count = data.getUInt8(); uint8_t track_nb = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerLapsVote(player_id, lap_count, - track_nb); + m_game_setup->getRaceConfig()->setPlayerLapsVote(player_id, lap_count, + track_nb); NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_LAPS).addUInt8(player_id).addUInt8(lap_count) .addUInt8(track_nb); @@ -749,11 +856,75 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event) delete other; } // playerLapsVote +// ---------------------------------------------------------------------------- +/** Called from the RaceManager of the server when the world is loaded. Marks + * the server to be ready to start the race. + */ +void ServerLobby::finishedLoadingWorld() +{ + m_server_has_loaded_world = true; +} // finishedLoadingWorld; + +//----------------------------------------------------------------------------- +/** Called when a client notifies the server that it has loaded the world. + * When all clients and the server are ready, the race can be started. + */ +void ServerLobby::finishedLoadingWorldClient(Event *event) +{ + if (!checkDataSize(event, 1)) return; + + const NetworkString &data = event->data(); + uint8_t player_count = data.getUInt8(); + m_client_ready_count.lock(); + for (unsigned int i = 0; i < player_count; i++) + { + uint8_t player_id = data.getUInt8(); + if (m_player_states[player_id]) + { + Log::error("ServerLobbyProtocol", + "Player %d send more than one ready message.", + player_id); + m_client_ready_count.unlock(); + return; + } + m_player_states[player_id] = true; + m_client_ready_count.getData()++; + Log::info("ServerLobbyeProtocol", "Player %d is ready (%d/%d).", + player_id, m_client_ready_count.getData(), + m_game_setup->getPlayerCount()); + } + m_client_ready_count.unlock(); + +} // finishedLoadingWorldClient + +//----------------------------------------------------------------------------- +/** Called when a notification from a client is received that the client has + * started the race. Once all clients have informed the server that they + * have started the race, the server can start. This makes sure that the + * server's local time is behind all clients by (at least) their latency, + * which in turn means that when the server simulates local time T all + * messages from clients at their local time T should have arrived at + * the server, which creates smoother play experience. + */ +void ServerLobby::startedRaceOnClient(Event *event) +{ + m_client_ready_count.lock(); + Log::verbose("ServerLobby", "Host %d has started race.", + event->getPeer()->getHostId()); + m_client_ready_count.getData()++; + if (m_client_ready_count.getData() == m_game_setup->getPlayerCount()) + { + m_state = DELAY_SERVER; + terminateLatencyProtocol(); + } + m_client_ready_count.unlock(); +} // startedRaceOnClient + //----------------------------------------------------------------------------- /** Called when a client clicks on 'ok' on the race result screen. * If all players have clicked on 'ok', go back to the lobby. */ -void ServerLobbyRoomProtocol::playerFinishedResult(Event *event) +void ServerLobby::playerFinishedResult(Event *event) { m_player_ready_counter++; if(m_player_ready_counter == STKHost::get()->getPeerCount()) diff --git a/src/network/protocols/server_lobby_room_protocol.hpp b/src/network/protocols/server_lobby.hpp similarity index 53% rename from src/network/protocols/server_lobby_room_protocol.hpp rename to src/network/protocols/server_lobby.hpp index 4a4cb697f..d358a545f 100644 --- a/src/network/protocols/server_lobby_room_protocol.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -1,21 +1,26 @@ -#ifndef SERVER_LOBBY_ROOM_PROTOCOL_HPP -#define SERVER_LOBBY_ROOM_PROTOCOL_HPP +#ifndef SERVER_LOBBY_HPP +#define SERVER_LOBBY_HPP -#include "network/protocols/lobby_room_protocol.hpp" +#include "network/protocols/lobby_protocol.hpp" #include "utils/cpp2011.hpp" #include "utils/synchronised.hpp" -class ServerLobbyRoomProtocol : public LobbyRoomProtocol - , public CallbackObject +class ServerLobby : public LobbyProtocol + , public CallbackObject { private: /* The state for a small finite state machine. */ enum { - NONE, + INIT_WAN, // Start state for WAN game GETTING_PUBLIC_ADDRESS, // Waiting to receive its public ip address ACCEPTING_CLIENTS, // In lobby, accepting clients SELECTING, // kart, track, ... selection started + LOAD_WORLD, // Server starts loading world + WAIT_FOR_WORLD_LOADED, // Wait for clients and server to load world + WAIT_FOR_RACE_STARTED, // Wait for all clients to have started the race + START_RACE, // Inform clients to start race + DELAY_SERVER, // Additional server delay RACING, // racing RESULT_DISPLAY, // Show result screen DONE, // shutting down server @@ -25,6 +30,22 @@ private: /** Next id to assign to a peer. */ Synchronised m_next_player_id; + /** Keeps track of the server state. */ + bool m_server_has_loaded_world; + + /** Counts how many clients have finished loading the world. */ + Synchronised m_client_ready_count; + + /** For debugging: keep track of the state (ready or not) of each player, + * to make sure no client/player reports more than once. Needs to be a + * map since the client IDs can be non-consecutive. */ + std::map m_player_states; + + /** Keeps track of an artificial server delay (which makes sure that the + * data from all clients has arrived when the server computes a certain + * timestep. */ + float m_server_delay; + Protocol *m_current_protocol; bool m_selection_enabled; @@ -48,23 +69,25 @@ private: void playerLapsVote(Event* event); void playerFinishedResult(Event *event); void registerServer(); - + void finishedLoadingWorldClient(Event *event); + void startedRaceOnClient(Event *event); public: - ServerLobbyRoomProtocol(); - virtual ~ServerLobbyRoomProtocol(); + ServerLobby(); + virtual ~ServerLobby(); virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; virtual void setup() OVERRIDE; virtual void update(float dt) OVERRIDE; virtual void asynchronousUpdate() OVERRIDE {}; - void startGame(); + void signalRaceStartToClients(); void startSelection(const Event *event=NULL); void checkIncomingConnectionRequests(); void checkRaceFinished(); + void finishedLoadingWorld(); virtual void callback(Protocol *protocol) OVERRIDE; -}; // class ServerLobbyRoomProtocol +}; // class ServerLobby -#endif // SERVER_LOBBY_ROOM_PROTOCOL_HPP +#endif // SERVER_LOBBY_HPP diff --git a/src/network/protocols/start_game_protocol.cpp b/src/network/protocols/start_game_protocol.cpp deleted file mode 100644 index 38ee66f35..000000000 --- a/src/network/protocols/start_game_protocol.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "network/protocols/start_game_protocol.hpp" - -#include "config/player_manager.hpp" -#include "input/device_manager.hpp" -#include "input/input_device.hpp" -#include "input/input_manager.hpp" -#include "challenges/unlock_manager.hpp" -#include "modes/world.hpp" -#include "network/event.hpp" -#include "network/game_setup.hpp" -#include "network/network_config.hpp" -#include "network/network_player_profile.hpp" -#include "network/race_event_manager.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/synchronization_protocol.hpp" -#include "network/stk_host.hpp" -#include "online/online_profile.hpp" -#include "race/race_manager.hpp" -#include "states_screens/kart_selection.hpp" -#include "states_screens/network_kart_selection.hpp" -#include "utils/log.hpp" -#include "utils/time.hpp" - -StartGameProtocol::StartGameProtocol(GameSetup* game_setup) - : Protocol(PROTOCOL_START_GAME) -{ - m_game_setup = game_setup; - const std::vector &players = - m_game_setup->getPlayers(); - for (unsigned int i = 0; i < players.size(); i++) - { - m_player_states[ players[i]->getGlobalPlayerId() ] = LOADING; - } - m_ready_count = 0; -} // StartGameProtocol - -// ---------------------------------------------------------------------------- -StartGameProtocol::~StartGameProtocol() -{ -} // ~StartGameProtocol - -// ---------------------------------------------------------------------------- -/** Setup the actual game. It first starts the SynchronisationProtocol, - * and then - */ -void StartGameProtocol::setup() -{ - m_state = NONE; - m_ready_count = 0; - m_ready = false; - Log::info("SynchronizationProtocol", "Ready !"); - - Protocol *p = new SynchronizationProtocol(); - p->requestStart(); - Log::info("StartGameProtocol", "SynchronizationProtocol started."); - - // Race startup sequence - // --------------------- - // This creates the network world. - RaceEventManager::getInstance()->start(); - - // The number of karts includes the AI karts, which are not supported atm - race_manager->setNumKarts(m_game_setup->getPlayerCount()); - - // Set number of global and local players. - race_manager->setNumPlayers(m_game_setup->getPlayerCount(), - m_game_setup->getNumLocalPlayers()); - - // Create the kart information for the race manager: - // ------------------------------------------------- - std::vector players = m_game_setup->getPlayers(); - int local_player_id = 0; - for (unsigned int i = 0; i < players.size(); i++) - { - NetworkPlayerProfile* profile = players[i]; - bool is_local = profile->isLocalPlayer(); - - // All non-local players are created here. This means all players - // on the server, and all non-local players on a client (the local - // karts are created in the NetworkingLobby). - if(!is_local) - { - // On the server no device or player profile is needed. - StateManager::get()->createActivePlayer(NULL, NULL); - } - - // Adjust the local player id so that local players have the numbers - // 0 to num-1; and all other karts start with num. This way the local - // players get the first ActivePlayers assigned (which have the - // corresponding device associated with it). - RemoteKartInfo rki(is_local ? local_player_id - : i-local_player_id - +STKHost::get()->getGameSetup()->getNumLocalPlayers(), - profile->getKartName(), - profile->getName(), - profile->getHostId(), - !is_local); - rki.setGlobalPlayerId(profile->getGlobalPlayerId()); - rki.setPerPlayerDifficulty(profile->getPerPlayerDifficulty()); - if(is_local) - { - rki.setLocalPlayerId(local_player_id); - local_player_id++; - } - - // Inform the race manager about the data for this kart. - race_manager->setPlayerKart(i, rki); - } // for i in players - - // Make sure that if there is only a single local player this player can - // use all input devices. - StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1 - ? NULL - : StateManager::get()->getActivePlayer(0); - - input_manager->getDeviceManager()->setSinglePlayer(ap); - - Log::info("StartGameProtocol", "Player configuration ready."); - m_state = SYNCHRONIZATION_WAIT; - -} // setup - -// ---------------------------------------------------------------------------- -/** Handles incoming messages on the server. Should never be called on a - * client. It counts how many clients are ready, and once all clients - * are ready, will call startRace(). - * \param event Details about the received mnessage. - */ -bool StartGameProtocol::notifyEventAsynchronous(Event* event) -{ - if(!checkDataSize(event, 1)) return true; - - const NetworkString &data = event->data(); - uint8_t player_id = data.getUInt8(); - uint8_t ready = data.getUInt8(); - if (NetworkConfig::get()->isServer() && ready) // on server, player is ready - { - Log::info("StartGameProtocol", "One of the players is ready."); - if (m_player_states[player_id] != LOADING) - { - Log::error("StartGameProtocol", - "Player %d send more than one ready message.", - player_id); - } - m_player_states[player_id] = READY; - m_ready_count++; - if (m_ready_count == m_game_setup->getPlayerCount()) - { - startRace(); - } // if m_ready_count == number of players - } - else // on the client, we shouldn't even receive messages. - { - Log::error("StartGameProtocol", "Received a message with bad format."); - } - return true; -} // notifyEventAsynchronous - -// ---------------------------------------------------------------------------- -/** Starts the race by starting the SynchronizationProtocol. - */ -void StartGameProtocol::startRace() -{ - // everybody ready, synchronize - Protocol *p = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_SYNCHRONIZATION); - SynchronizationProtocol* protocol = - dynamic_cast(p); - if (protocol) - { - protocol->startCountdown(5.0f); // 5 seconds countdown - Log::info("StartGameProtocol", - "All players ready, starting countdown."); - m_ready = true; - } - else - { - Log::error("StartGameProtocol", - "The Synchronization protocol hasn't been started."); - } -} // startRace - -// ---------------------------------------------------------------------------- -void StartGameProtocol::update(float dt) -{ - switch(m_state) - { - case SYNCHRONIZATION_WAIT: - { - // Wait till the synchronisation protocol is running - Protocol *p = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_SYNCHRONIZATION); - SynchronizationProtocol* protocol = - dynamic_cast(p); - if (protocol) - { - // Now the synchronization protocol exists. - Log::info("StartGameProtocol", "Starting the race loading."); - // This will create the world instance, - // i.e. load track and karts - m_game_setup->getRaceConfig()->setRaceData(); - World::getWorld()->setNetworkWorld(true); - m_state = LOADING; - } - break; - } - case LOADING: - { - if (m_ready) m_state = READY; - break; - } - case READY: - { - // set karts into the network game setup - STKHost::get()->getGameSetup()->bindKartsToProfiles(); - m_state = EXITING; - requestTerminate(); - break; - } - } // switch -} // update - -// ---------------------------------------------------------------------------- -/** Callback from the race manager when the world was setup. - */ -void StartGameProtocol::ready() -{ - // On clients this means the loading is finished. - // Inform the server that this client is ready. - if (NetworkConfig::get()->isClient()) - { - assert(STKHost::get()->getPeerCount() == 1); - std::vector players = - STKHost::get()->getMyPlayerProfiles(); - for(unsigned int i=0; iaddUInt8(players[i]->getGlobalPlayerId()).addUInt8(1); - Log::info("StartGameProtocol", "Player %d ready, notifying server.", - players[i]->getGlobalPlayerId()); - sendToServer(ns, /*reliable*/true); - delete ns; - } - m_state = READY; - m_ready = true; - return; - } -} // ready - diff --git a/src/network/protocols/start_game_protocol.hpp b/src/network/protocols/start_game_protocol.hpp deleted file mode 100644 index c300a5bbf..000000000 --- a/src/network/protocols/start_game_protocol.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef START_GAME_PROTOCOL_HPP -#define START_GAME_PROTOCOL_HPP - -#include "network/protocol.hpp" -#include "utils/cpp2011.hpp" - -#include - -class GameSetup; -class NetworkPlayerProfile; - -/** This protocol runs on both server and clients. - */ -class StartGameProtocol : public Protocol -{ -private: - /** State for the finite state machine, and also for - * remote clients. */ - enum STATE { NONE, SYNCHRONIZATION_WAIT, - LOADING, READY, EXITING }; - - /** State of the finite state machine. */ - STATE m_state; - - /** Keeps the state for all clients. */ - std::map m_player_states; - - /** Stores a handy pointer to the game setup structure. */ - GameSetup* m_game_setup; - - /** Counts how many clients have reported to be ready (which is then - * used to trigger the next state one all clients are ready). */ - int m_ready_count; - - bool m_ready; - - void startRace(); - -public: - StartGameProtocol(GameSetup* game_setup); - virtual ~StartGameProtocol(); - - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup() OVERRIDE; - virtual void update(float dt) OVERRIDE; - void ready(); - virtual void asynchronousUpdate() OVERRIDE {} - -}; // class StartGameProtocol - -#endif // START_GAME_PROTOCOL_HPP diff --git a/src/network/protocols/synchronization_protocol.cpp b/src/network/protocols/synchronization_protocol.cpp deleted file mode 100644 index a1d202276..000000000 --- a/src/network/protocols/synchronization_protocol.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "network/protocols/synchronization_protocol.hpp" - -#include "network/event.hpp" -#include "network/network_config.hpp" -#include "network/protocols/kart_update_protocol.hpp" -#include "network/protocols/controller_events_protocol.hpp" -#include "network/protocols/game_events_protocol.hpp" -#include "network/stk_host.hpp" -#include "network/stk_peer.hpp" -#include "utils/time.hpp" - -//----------------------------------------------------------------------------- - -SynchronizationProtocol::SynchronizationProtocol() - : Protocol(PROTOCOL_SYNCHRONIZATION) -{ - unsigned int size = STKHost::get()->getPeerCount(); - m_pings.resize(size, std::map()); - m_successed_pings.resize(size, 0); - m_total_diff.resize(size, 0); - m_average_ping.resize(size, 0); - m_pings_count = 0; - m_countdown_activated = false; - m_last_time = -1; -} // SynchronizationProtocol - -//----------------------------------------------------------------------------- -SynchronizationProtocol::~SynchronizationProtocol() -{ -} // ~SynchronizationProtocol - -//----------------------------------------------------------------------------- -void SynchronizationProtocol::setup() -{ - Log::info("SynchronizationProtocol", "Ready !"); - m_countdown = 5.0; // init the countdown to 5s - m_has_quit = false; -} // setup - //----------------------------------------------------------------------------- -/** Called when receiving a message. On the client side the message is a ping - * from the server, which is answered back. The client will also check if the - * server has started the countdown (which is indicated in the ping message). - * On the server the received message is a reply to a previous ping request. - * The server will keep track of average latency. - */ -bool SynchronizationProtocol::notifyEventAsynchronous(Event* event) -{ - if (event->getType() != EVENT_TYPE_MESSAGE) - return true; - if(!checkDataSize(event, 5)) return true; - - const NetworkString &data = event->data(); - uint32_t request = data.getUInt8(); - uint32_t sequence = data.getUInt32(); - - const std::vector &peers = STKHost::get()->getPeers(); - assert(peers.size() > 0); - - // Find the right peer id. The host id (i.e. each host sendings its - // host id) can not be used here, since host ids can have gaps (if a - // host should disconnect) - uint8_t peer_id = -1; - for (unsigned int i = 0; i < peers.size(); i++) - { - if (peers[i]->isSamePeer(event->getPeer())) - { - peer_id = i; - break; - } - } - - if (request) - { - // Only a client should receive a request for a ping response - assert(NetworkConfig::get()->isClient()); - NetworkString *response = getNetworkString(5); - // The '0' indicates a response to a ping request - response->addUInt8(0).addUInt32(sequence); - event->getPeer()->sendPacket(response, false); - delete response; - Log::verbose("SynchronizationProtocol", "Answering sequence %u at %lf", - sequence, StkTime::getRealTime()); - - // countdown time in the message - if (data.size() == 4) - { - float time_to_start = data.getFloat(); - Log::debug("SynchronizationProtocol", - "Request to start game in %f.", time_to_start); - if (!m_countdown_activated) - startCountdown(time_to_start); - else - { - // Adjust the time based on the value sent from the server. - m_countdown = time_to_start; - } - } - else - Log::verbose("SynchronizationProtocol", "No countdown for now."); - } - else // receive response to a ping request - { - // Only a server should receive this kind of message - assert(NetworkConfig::get()->isServer()); - if (sequence >= m_pings[peer_id].size()) - { - Log::warn("SynchronizationProtocol", - "The sequence# %u isn't known.", sequence); - return true; - } - double current_time = StkTime::getRealTime(); - m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence]; - m_successed_pings[peer_id]++; - m_average_ping[peer_id] = - (int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0); - - Log::debug("SynchronizationProtocol", - "Peer %d sequence %d ping %u average %u at %lf", - peer_id, sequence, - (unsigned int)((current_time - m_pings[peer_id][sequence])*1000), - m_average_ping[peer_id], - StkTime::getRealTime()); - } - return true; -} // notifyEventAsynchronous - -//----------------------------------------------------------------------------- -/** Waits for the countdown to be started. On the server the start of the - * countdown is triggered by the StartGameProtocol::startRace(), which is - * called once all clients have confirmed that they are ready to start. - * The server will send a ping request to each client once a second, and - * include the information if the countdown has started (and its current - * value). On the client the countdown is started in notifyEvenAsynchronous() - * when a server ping is received that indicates that the countdown has - * started. The measured times can be used later to estimate the latency - * between server and client. - */ -void SynchronizationProtocol::asynchronousUpdate() -{ - float current_time = float(StkTime::getRealTime()); - if (m_countdown_activated) - { - m_countdown -= (current_time - m_last_countdown_update); - m_last_countdown_update = current_time; - Log::debug("SynchronizationProtocol", - "Update! Countdown remaining : %f", m_countdown); - if (m_countdown < 0.0 && !m_has_quit) - { - m_has_quit = true; - Log::info("SynchronizationProtocol", - "Countdown finished. Starting now."); - (new KartUpdateProtocol())->requestStart(); - (new ControllerEventsProtocol())->requestStart(); - (new GameEventsProtocol())->requestStart(); - requestTerminate(); - return; - } - } // if m_countdown_activated - - if (NetworkConfig::get()->isServer() && current_time > m_last_time+1) - { - const std::vector &peers = STKHost::get()->getPeers(); - for (unsigned int i = 0; i < peers.size(); i++) - { - NetworkString *ping_request = - getNetworkString(m_countdown_activated ? 9 : 5); - ping_request->addUInt8(1).addUInt32(m_pings[i].size()); - // Server adds the countdown if it has started. This will indicate - // to the client to start the countdown as well (first time the - // message is received), or to update the countdown time. - if (m_countdown_activated) - { - ping_request->addFloat(m_countdown); - Log::debug("SynchronizationProtocol", - "CNTActivated: Countdown value : %f", m_countdown); - } - Log::verbose("SynchronizationProtocol", - "Added sequence number %u for peer %d at %lf", - m_pings[i].size(), i, StkTime::getRealTime()); - m_pings[i] [ m_pings_count ] = current_time; - peers[i]->sendPacket(ping_request, false); - delete ping_request; - } // for i M peers - m_last_time = current_time; - m_pings_count++; - } // if current_time > m_last_time + 0.1 -} // asynchronousUpdate - -//----------------------------------------------------------------------------- -/** Starts the countdown on this machine. On the server side this function - * is called from the StartGameProtocol (when all players have confirmed that - * they are ready to play). On the client side this function is called from - * this protocol when a message from the server is received indicating that - * the countdown has to be started. - * \param ms_countdown Countdown to use in ms. - */ -void SynchronizationProtocol::startCountdown(float ms_countdown) -{ - m_countdown_activated = true; - m_countdown = ms_countdown; - m_last_countdown_update = float(StkTime::getRealTime()); - Log::info("SynchronizationProtocol", "Countdown started with value %f", - m_countdown); -} // startCountdown diff --git a/src/network/protocols/synchronization_protocol.hpp b/src/network/protocols/synchronization_protocol.hpp deleted file mode 100644 index ed586fa11..000000000 --- a/src/network/protocols/synchronization_protocol.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef SYNCHRONIZATION_PROTOCOL_HPP -#define SYNCHRONIZATION_PROTOCOL_HPP - -#include "network/protocol.hpp" -#include "utils/cpp2011.hpp" - -#include -#include - -class SynchronizationProtocol : public Protocol -{ -private: - std::vector > m_pings; - std::vector m_average_ping; - - /** Counts the number of pings sent. */ - uint32_t m_pings_count; - std::vector m_successed_pings; - std::vector m_total_diff; - - /** True if the countdown has started, i.e. all clients have loaded - * the track and karts. */ - bool m_countdown_activated; - - /** The countdown timer value. */ - float m_countdown; - float m_last_countdown_update; - bool m_has_quit; - - /** Keeps track of last time that an update was sent. */ - double m_last_time; - - -public: - SynchronizationProtocol(); - virtual ~SynchronizationProtocol(); - - virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; - virtual void setup() OVERRIDE; - virtual void asynchronousUpdate() OVERRIDE; - void startCountdown(float ms_countdown); - - // ------------------------------------------------------------------------ - virtual void update(float dt) OVERRIDE {} - // ------------------------------------------------------------------------ - /** Returns the current countdown value. */ - float getCountdown() { return m_countdown; } - -}; // class SynchronizationProtocol - -#endif // SYNCHRONIZATION_PROTOCOL_HPP diff --git a/src/network/race_config.cpp b/src/network/race_config.cpp index c300403cc..26f57e218 100644 --- a/src/network/race_config.cpp +++ b/src/network/race_config.cpp @@ -421,15 +421,15 @@ void RaceConfig::computeNextTrack() //----------------------------------------------------------------------------- /** Computes the selected setting (based on the users' vote) and sets them - * in the race manager. + * in the race manager. Then it loads the world. */ -void RaceConfig::setRaceData() +void RaceConfig::loadWorld() { computeRaceMode(); computeNextTrack(); race_manager->startSingleRace(m_tracks[0].track, m_tracks[0].laps, m_tracks[0].reversed); -} // setRaceData +} // loadWorld //----------------------------------------------------------------------------- const TrackInfo* RaceConfig::getNextTrackInfo() const diff --git a/src/network/race_config.hpp b/src/network/race_config.hpp index 5d96234b3..e88979862 100644 --- a/src/network/race_config.hpp +++ b/src/network/race_config.hpp @@ -110,7 +110,7 @@ public: void setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb = 0); - void setRaceData(); + void loadWorld(); const TrackInfo* getNextTrackInfo() const; bool getReverse() const; diff --git a/src/network/race_event_manager.cpp b/src/network/race_event_manager.cpp index c4112ab20..bc86d853c 100644 --- a/src/network/race_event_manager.cpp +++ b/src/network/race_event_manager.cpp @@ -5,7 +5,6 @@ #include "modes/world.hpp" #include "network/network_config.hpp" #include "network/protocol_manager.hpp" -#include "network/protocols/synchronization_protocol.hpp" #include "network/protocols/controller_events_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" @@ -22,9 +21,7 @@ RaceEventManager::~RaceEventManager() // ---------------------------------------------------------------------------- /** In network games this update function is called instead of - * World::updateWorld(). This allow this function to postpone calling - * the worl update while the countdown from the SynchronisationProtocol is - * running. + * World::updateWorld(). */ void RaceEventManager::update(float dt) { @@ -33,18 +30,6 @@ void RaceEventManager::update(float dt) if(!ProtocolManager::getInstance()) return; - SynchronizationProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_SYNCHRONIZATION)); - if (protocol) // The existance of this protocol indicates that we play online - { - Log::debug("RaceEventManager", "Countdown value is %f", - protocol->getCountdown()); - if (protocol->getCountdown() > 0.0) - { - return; - } - World::getWorld()->setNetworkWorld(true); - } World::getWorld()->updateWorld(dt); // if the race is over @@ -100,21 +85,6 @@ void RaceEventManager::collectedItem(Item *item, AbstractKart *kart) protocol->collectedItem(item,kart); } // collectedItem -// ---------------------------------------------------------------------------- -/** A message from the server to all clients that it is now starting the - * 'ready' phase. Clients will wait for this event before they display - * RSG. This will make sure that the server time is always ahead of - * the client time. - */ -void RaceEventManager::startReadySetGo() -{ - // this is only called in the server - assert(NetworkConfig::get()->isServer()); - - GameEventsProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS)); - protocol->startReadySetGo(); -} // startReadySetGo // ---------------------------------------------------------------------------- void RaceEventManager::controllerAction(Controller* controller, PlayerAction action, int value) diff --git a/src/network/race_event_manager.hpp b/src/network/race_event_manager.hpp index f224c2cff..9a5febe1e 100755 --- a/src/network/race_event_manager.hpp +++ b/src/network/race_event_manager.hpp @@ -56,7 +56,6 @@ public: void controllerAction(Controller* controller, PlayerAction action, int value); void kartFinishedRace(AbstractKart *kart, float time); - void startReadySetGo(); // ------------------------------------------------------------------------ /** Returns if this instance is in running state or not. */ bool isRunning() { return m_running; } diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index d9c4d8523..0583a88a9 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -26,7 +26,7 @@ #include "network/network_string.hpp" #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/connect_to_server.hpp" -#include "network/protocols/server_lobby_room_protocol.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/protocol_manager.hpp" #include "network/servers_manager.hpp" #include "network/stk_peer.hpp" @@ -101,7 +101,7 @@ void STKHost::create() * * Server: * - * 1. ServerLobbyRoomProtocol: + * 1. ServerLobby: * Spawns the following sub-protocols: * 1. GetPublicAddress: Use STUN to discover the public ip address * and port number of this host. @@ -141,7 +141,7 @@ void STKHost::create() * * Server: * - * The ServerLobbyRoomProtocol (SLR) will then detect the above client + * The ServerLobby (SLR) will then detect the above client * requests, and start a ConnectToPeer protocol for each incoming client. * The ConnectToPeer protocol uses: * 1. GetPeerAddress to get the ip address and port of the client. @@ -151,7 +151,7 @@ void STKHost::create() * destination (unless if it is a LAN connection, then UDP * broadcasts will be used). * - * Each client will run a ClientLobbyRoomProtocol (CLR) to handle the further + * Each client will run a ClientLobbyProtocol (CLR) to handle the further * interaction with the server. The client will first request a connection * with the server (this is for the 'logical' connection to the server; so * far it was mostly about the 'physical' connection, i.e. being able to send @@ -162,7 +162,7 @@ void STKHost::create() * each received message to the protocol with the same id. So any message * sent by protocol X on the server will be received by protocol X on the * client and vice versa. The only exception are the client- and server-lobby: - * They share the same id (set in LobbyRoomProtocol), so a message sent by + * They share the same id (set in LobbyProtocol), so a message sent by * the SLR will be received by the CLR, and a message from the CLR will be * received by the SLR. * @@ -206,25 +206,24 @@ void STKHost::create() * stored in RaceConfig of GameSetup. * * The server will detect when the track votes from each client have been - * received and will trigger the start of the race (SLR::startGame, called - * from playerTrackVote). In SLR::startGame the server will start the - * StartGameProtocol and the clients will be informed to start the game. - * In a client the StartGame protocol will be started in CLR::startGame. + * received and will inform all clients to load the world (playerTrackVote). + * Then (state LOAD_GAME) the server will load the world and wait for all + * clients to finish loading (WAIT_FOR_WORLD_LOADED). * - * The StartGame protocol will create the ActivePlayers for all non-local - * players: on a server, all karts are non-local. On a client, the - * ActivePlayer objects for each local players have been created (to store - * the device used by each player when joining), so they are used to create - * the LocalPlayerController for each kart. Each remote player gets a + * In LR::loadWorld all ActivePlayers for all non-local players are created. + * (on a server all karts are non-local). On a client, the ActivePlayer + * objects for each local players have been created (to store the device + * used by each player when joining), so they are used to create the + * LocalPlayerController for each kart. Each remote player gets a * NULL ActivePlayer (the ActivePlayer is only used for assigning the input * device to each kart, achievements and highscores, so it's not needed for - * remote players). It will also start the SynchronizationProtocol. - * The StartGameProtocol has a callback ready() which is called from world - * when the world is loaded (i.e. track and all karts are ready). When - * this callback is invoked, each client will send a 'ready' message to - * the server's StartGameProtocol. Once the server has received all + * remote players). It will also start the LatencyProtocol, + * RaceEventManager and then load the world. + + * TODO: + * Once the server has received all * messages in notifyEventAsynchronous(), it will call startCountdown() - * in the SynchronizationProtocol. The SynchronizationProtocol is + * in the LatencyProtocol. The LatencyProtocol is * sending regular (once per second) pings to the clients and measure * the averate latency. Upon starting the countdown this information * is included in the ping request, so the clients can start the countdown @@ -232,7 +231,7 @@ void STKHost::create() * * Once the countdown is 0 (or below), the Synchronization Protocol will * start the protocols: KartUpdateProtocol, ControllerEventsProtocol, - * GameEventsProtocol. Then the SynchronizationProtocol is terminated + * GameEventsProtocol. Then the LatencyProtocol is terminated * which indicates to the main loop to start the actual game. */ @@ -265,7 +264,7 @@ STKHost::STKHost(uint32_t server_id, uint32_t host_id) // ---------------------------------------------------------------------------- /** The constructor for a server. - * The server control flow starts with the ServerLobbyRoomProtocol. + * The server control flow starts with the ServerLobby. */ STKHost::STKHost(const irr::core::stringw &server_name) { @@ -290,7 +289,8 @@ STKHost::STKHost(const irr::core::stringw &server_name) } startListening(); - ProtocolManager::getInstance()->requestStart(new ServerLobbyRoomProtocol()); + Protocol *p = LobbyProtocol::create(); + ProtocolManager::getInstance()->requestStart(p); } // STKHost(server_name) @@ -529,7 +529,7 @@ void* STKHost::mainLoop(void* self) ENetHost* host = myself->m_network->getENetHost(); if(NetworkConfig::get()->isServer() && - NetworkConfig::get()->isLAN() ) + (NetworkConfig::get()->isLAN() || NetworkConfig::get()->isPublicServer()) ) { TransportAddress address(0, NetworkConfig::get()->getServerDiscoveryPort()); ENetAddress eaddr = address.toEnetAddress(); @@ -540,7 +540,7 @@ void* STKHost::mainLoop(void* self) { if(myself->m_lan_network) { - myself->handleLANRequests(); + myself->handleDirectSocketRequest(); } // if discovery host while (enet_host_service(host, &event, 20) != 0) @@ -585,11 +585,15 @@ void* STKHost::mainLoop(void* self) } // mainLoop // ---------------------------------------------------------------------------- -/** Handles LAN related messages. It checks for any LAN broadcast messages, - * and if a valid LAN server-request message is received, will answer - * with a message containing server details (and sender IP address and port). +/** Handles a direct request given to a socket. This is typically a LAN + * request, but can also be used if the server is public (i.e. not behind + * a fire wall) to allow direct connection to the server (without using the + * STK server). It checks for any messages (i.e. a LAN broadcast requesting + * server details or a connection request) and if a valid LAN server-request + * message is received, will answer with a message containing server details + * (and sender IP address and port). */ -void STKHost::handleLANRequests() +void STKHost::handleDirectSocketRequest() { const int LEN=2048; char buffer[LEN]; @@ -600,6 +604,7 @@ void STKHost::handleLANRequests() BareNetworkString message(buffer, len); std::string command; message.decodeString(&command); + if (command == "stk-server") { Log::verbose("STKHost", "Received LAN server query"); @@ -625,6 +630,15 @@ void STKHost::handleLANRequests() } // if message is server-requested else if (command == "connection-request") { + // In case of a LAN connection, we only allow connections from + // a LAN address (192.168*, ..., and 127.*). + if (NetworkConfig::get()->isLAN() && !sender.isLAN()) + { + Log::error("STKHost", "Client trying to connect from '%s'", + sender.toString().c_str()); + Log::error("STKHost", "which is outside of LAN - rejected."); + return; + } Protocol *c = new ConnectToPeer(sender); c->requestStart(); } @@ -632,7 +646,7 @@ void STKHost::handleLANRequests() Log::info("STKHost", "Received unknown command '%s'", std::string(buffer, len).c_str()); -} // handleLANRequests +} // handleDirectSocketRequest // ---------------------------------------------------------------------------- /** \brief Tells if a peer is known. diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 0f526fdb2..ae1be86e0 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -109,7 +109,7 @@ private: STKHost(const irr::core::stringw &server_name); virtual ~STKHost(); void init(); - void handleLANRequests(); + void handleDirectSocketRequest(); public: /** If a network console should be started. Note that the console can cause diff --git a/src/network/transport_address.cpp b/src/network/transport_address.cpp new file mode 100644 index 000000000..f4aa09e29 --- /dev/null +++ b/src/network/transport_address.cpp @@ -0,0 +1,112 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "network/transport_address.hpp" + +/** Returns if this IP address belongs to a LAN, i.e. is in 192.168* or + * 10*, 172.16-31.*, or is on the same host, i.e. 127*. + */ +bool TransportAddress::isLAN() const +{ + uint32_t ip = getIP(); + if (ip >> 16 == 0xc0a8) // Check for 192.168.* + return true; + else if (ip >> 20 == 0xac1 ) // 172.16-31.* + return true; + else if (ip >> 24 == 0x0a ) // 10.* + return true; + else if (ip >> 24 == 0x7f ) // 127.* localhost + return true; + return false; +} // isLAN + +// ---------------------------------------------------------------------------- +/** Unit testing. Test various LAN patterns to verify that isLAN() works as + * expected. + */ +void TransportAddress::unitTesting() +{ + TransportAddress t1("192.168.0.0"); + assert(t1.getIP() == (192 << 24) + (168 << 16)); + assert(t1.isLAN()); + + TransportAddress t2("192.168.255.255"); + assert(t2.getIP() == (192 << 24) + (168 << 16) + (255 << 8) + 255); + assert(t2.isLAN()); + + TransportAddress t3("193.168.0.1"); + assert(t3.getIP() == (193 << 24) + (168 << 16) + 1); + assert(!t3.isLAN()); + + TransportAddress t4("192.167.255.255"); + assert(t4.getIP() == (192 << 24) + (167 << 16) + (255 << 8) + 255); + assert(!t4.isLAN()); + + TransportAddress t5("192.169.0.0"); + assert(t5.getIP() == (192 << 24) + (169 << 16)); + assert(!t5.isLAN()); + + TransportAddress t6("172.16.0.0"); + assert(t6.getIP() == (172 << 24) + (16 << 16)); + assert(t6.isLAN()); + + TransportAddress t7("172.31.255.255"); + assert(t7.getIP() == (172 << 24) + (31 << 16) + (255 << 8) + 255); + assert(t7.isLAN()); + + TransportAddress t8("172.15.255.255"); + assert(t8.getIP() == (172 << 24) + (15 << 16) + (255 << 8) + 255); + assert(!t8.isLAN()); + + TransportAddress t9("172.32.0.0"); + assert(t9.getIP() == (172 << 24) + (32 << 16)); + assert(!t9.isLAN()); + + TransportAddress t10("10.0.0.0"); + assert(t10.getIP() == (10 << 24)); + assert(t10.isLAN()); + + TransportAddress t11("10.255.255.255"); + assert(t11.getIP() == (10 << 24) + (255 << 16) + (255 << 8) + 255); + assert(t11.isLAN()); + + TransportAddress t12("9.255.255.255"); + assert(t12.getIP() == (9 << 24) + (255 << 16) + (255 << 8) + 255); + assert(!t12.isLAN()); + + TransportAddress t13("11.0.0.0"); + assert(t13.getIP() == (11 << 24) ); + assert(!t13.isLAN()); + + TransportAddress t14("127.0.0.0"); + assert(t14.getIP() == (127 << 24)); + assert(t14.isLAN()); + + TransportAddress t15("127.255.255.255"); + assert(t15.getIP() == (127 << 24) + (255 << 16) + (255 << 8) + 255); + assert(t15.isLAN()); + + TransportAddress t16("126.255.255.255"); + assert(t16.getIP() == (126 << 24) + (255 << 16) + (255 << 8) + 255); + assert(!t16.isLAN()); + + TransportAddress t17("128.0.0.0"); + assert(t17.getIP() == (128 << 24)); + assert(t17.isLAN()); + +} // unitTesting \ No newline at end of file diff --git a/src/network/transport_address.hpp b/src/network/transport_address.hpp index 08b886715..2e33fb01f 100644 --- a/src/network/transport_address.hpp +++ b/src/network/transport_address.hpp @@ -57,9 +57,27 @@ public: m_port = a.port; } // TransportAddress(EnetAddress) + // ------------------------------------------------------------------------ + /** Construct an IO address from a string in the format x.x.x.x:xxx. */ + TransportAddress(const std::string& str) + { + std::string combined = StringUtils::replace(str, ":", "."); + std::vector ip = StringUtils::splitToUInt(combined, '.'); + m_ip = 0; + m_port = 0; + if (ip.size() >= 4) + m_ip = (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; + + if(ip.size()==5) + m_port = (uint16_t)(ip[4] < 65536 ? ip[4] : 0); + else + m_port = 0; + } // TransportAddress(string of ip) + // ------------------------------------------------------------------------ ~TransportAddress() {} // ------------------------------------------------------------------------ + static void unitTesting(); private: friend class NetworkConfig; /** The copy constructor is private, so that the friend class @@ -70,6 +88,7 @@ private: copy(other); } // TransportAddress(const TransportAddress&) public: + bool isLAN() const; // ------------------------------------------------------------------------ /** A copy function (to replace the copy constructor which is disabled * using NoCopy): it copies the data from the argument into this object.*/ diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 011208291..7808712a1 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -45,7 +45,7 @@ #include "modes/soccer_world.hpp" #include "network/protocol_manager.hpp" #include "network/network_config.hpp" -#include "network/protocols/start_game_protocol.hpp" +#include "network/protocols/lobby_protocol.hpp" #include "network/race_event_manager.hpp" #include "replay/replay_play.hpp" #include "scriptengine/property_animator.hpp" @@ -560,10 +560,9 @@ void RaceManager::startNextRace() // the world has been setup if(NetworkConfig::get()->isNetworking()) { - StartGameProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_START_GAME)); - if (protocol) - protocol->ready(); + LobbyProtocol *lobby = LobbyProtocol::get(); + assert(lobby); + lobby->finishedLoadingWorld(); } } // startNextRace diff --git a/src/scriptengine/script_track.cpp b/src/scriptengine/script_track.cpp index 7b3b4fb68..a4abe595d 100644 --- a/src/scriptengine/script_track.cpp +++ b/src/scriptengine/script_track.cpp @@ -94,7 +94,7 @@ namespace Scripting core::dimension2d textsize = digit_face->getDimension(wtext.c_str()); core::vector3df xyz(location->getX(), location->getY(), location->getZ()); - +#ifndef SERVER_ONLY if (CVS->isGLSL()) { STKTextBillboard* tb = new STKTextBillboard(wtext.c_str(), digit_face, @@ -123,6 +123,7 @@ namespace Scripting GUIEngine::getSkin()->getColor("font::top")); World::getWorld()->getTrack()->addNode(sn); } +#endif } /** Exits the race to the main menu */ diff --git a/src/states_screens/cutscene_gui.cpp b/src/states_screens/cutscene_gui.cpp index 38fdf0ba2..5a4ede064 100644 --- a/src/states_screens/cutscene_gui.cpp +++ b/src/states_screens/cutscene_gui.cpp @@ -40,6 +40,7 @@ CutsceneGUI::~CutsceneGUI() void CutsceneGUI::renderGlobal(float dt) { +#ifndef SERVER_ONLY core::dimension2d screen_size = irr_driver->getActualScreenSize(); if (m_fade_level > 0.0f) @@ -67,5 +68,6 @@ void CutsceneGUI::renderGlobal(float dt) video::SColor(255,255,255,255), true, true, NULL); } } +#endif } diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 31fafeed4..ccfccf71c 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -52,6 +52,7 @@ CustomVideoSettingsDialog::~CustomVideoSettingsDialog() void CustomVideoSettingsDialog::beforeAddingWidgets() { +#ifndef SERVER_ONLY getWidget("anim_gfx")->setState(UserConfigParams::m_graphical_effects); getWidget("weather_gfx")->setState(UserConfigParams::m_weather_effects); getWidget("dof")->setState(UserConfigParams::m_dof); @@ -115,12 +116,14 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() shadows->setActive(false); getWidget("global_illumination")->setActive(false); } +#endif } // ----------------------------------------------------------------------------- GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::string& eventSource) { +#ifndef SERVER_ONLY if (eventSource == "close") { bool advanced_pipeline = getWidget("dynamiclight")->getState(); @@ -219,7 +222,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s { updateActivation(); } - +#endif return GUIEngine::EVENT_LET; } // processEvent @@ -227,6 +230,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s void CustomVideoSettingsDialog::updateActivation() { +#ifndef SERVER_ONLY bool light = getWidget("dynamiclight")->getState(); getWidget("motionblur")->setActive(light); getWidget("dof")->setActive(light); @@ -244,5 +248,6 @@ void CustomVideoSettingsDialog::updateActivation() getWidget("shadows")->setActive(false); getWidget("global_illumination")->setActive(false); } +#endif } // updateActivation diff --git a/src/states_screens/network_kart_selection.cpp b/src/states_screens/network_kart_selection.cpp index 071d40ae2..36735d127 100644 --- a/src/states_screens/network_kart_selection.cpp +++ b/src/states_screens/network_kart_selection.cpp @@ -28,7 +28,7 @@ #include "karts/kart_properties_manager.hpp" #include "network/network_player_profile.hpp" #include "network/protocol_manager.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" #include "network/stk_host.hpp" #include "states_screens/server_selection.hpp" #include "states_screens/state_manager.hpp" @@ -133,8 +133,10 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID) } if(playerID == PLAYER_ID_GAME_MASTER) // self { - ClientLobbyRoomProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); + + LobbyProtocol* protocol = LobbyProtocol::get(); + ClientLobby *clrp = dynamic_cast(protocol); + assert(clrp); // FIXME SPLITSCREEN: we need to supply the global player id of the // player selecting the kart here. For now ... just vote the same kart // for each local player. @@ -142,7 +144,7 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID) STKHost::get()->getMyPlayerProfiles(); for(unsigned int i=0; irequestKartSelection(players[i]->getGlobalPlayerId(), + clrp->requestKartSelection(players[i]->getGlobalPlayerId(), selection); } } @@ -178,9 +180,9 @@ void NetworkKartSelectionScreen::playerSelected(uint8_t player_id, { Protocol* protocol = ProtocolManager::getInstance() ->getProtocol(PROTOCOL_LOBBY_ROOM); - ClientLobbyRoomProtocol* clrp = - static_cast(protocol); - + ClientLobby* clrp = + dynamic_cast(protocol); + assert(clrp); // FIXME: for now we submit a vote from the authorised user // for the various modes based on the settings in the race manager. // This needs more/better gui elements (and some should be set when @@ -209,10 +211,11 @@ bool NetworkKartSelectionScreen::onEscapePressed() // then remove the lobby screen (you left the server) StateManager::get()->popMenu(); ServerSelection::getInstance()->refresh(); + Protocol *lobby = LobbyProtocol::get(); // notify the server that we left - ClientLobbyRoomProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); - if (protocol) - protocol->leave(); + ClientLobby* clrp = + dynamic_cast(lobby); + if (clrp) + clrp->leave(); return true; // remove the screen } // onEscapePressed diff --git a/src/states_screens/networking_lobby.cpp b/src/states_screens/networking_lobby.cpp index b8c908c5f..736c47dea 100644 --- a/src/states_screens/networking_lobby.cpp +++ b/src/states_screens/networking_lobby.cpp @@ -34,9 +34,8 @@ #include "input/input_manager.hpp" #include "io/file_manager.hpp" #include "network/network_player_profile.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" -#include "network/protocols/server_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/servers_manager.hpp" #include "network/stk_host.hpp" #include "states_screens/state_manager.hpp" @@ -57,7 +56,7 @@ DEFINE_SCREEN_SINGLETON( NetworkingLobby ); * for all local players (the ActivePlayer maps device to player, i.e. * controls which device is used by which player). Note that a server * does not create an instance of this class and will create the ActivePlayer - * data structure in the StartGameProtocol. + * data structure in LobbyProtocol::loadWorld(). */ // ---------------------------------------------------------------------------- NetworkingLobby::NetworkingLobby() : Screen("online/networking_lobby.stkgui") @@ -163,16 +162,15 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, { if(NetworkConfig::get()->isServer()) { - ServerLobbyRoomProtocol* slrp = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); - if (slrp) - slrp->startSelection(); + Protocol *p = LobbyProtocol::get(); + ServerLobby* slrp = dynamic_cast(p); + slrp->startSelection(); } else // client { // Send a message to the server to start NetworkString start(PROTOCOL_LOBBY_ROOM); - start.addUInt8(LobbyRoomProtocol::LE_REQUEST_BEGIN); + start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); STKHost::get()->sendToServer(&start, true); } } @@ -199,8 +197,8 @@ void NetworkingLobby::tearDown() bool NetworkingLobby::onEscapePressed() { // notify the server that we left - ClientLobbyRoomProtocol* protocol = dynamic_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM)); + ClientLobby* protocol = + dynamic_cast(LobbyProtocol::get()); if (protocol) protocol->leave(); STKHost::get()->shutdown(); diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index 673013226..fdcc68d25 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -27,6 +27,9 @@ using namespace irr; #include "config/user_config.hpp" #include "graphics/camera.hpp" #include "graphics/2dutils.hpp" +#ifndef SERVER_ONLY +#include "graphics/glwrap.hpp" +#endif #include "graphics/irr_driver.hpp" #include "graphics/material_manager.hpp" #include "guiengine/engine.hpp" @@ -165,6 +168,7 @@ void RaceGUI::reset() */ void RaceGUI::renderGlobal(float dt) { +#ifndef SERVER_ONLY RaceGUIBase::renderGlobal(dt); cleanupMessages(dt); @@ -213,6 +217,7 @@ void RaceGUI::renderGlobal(float dt) if (!m_is_tutorial) drawGlobalPlayerIcons(m_map_height); if(world->getTrack()->isSoccer()) drawScores(); +#endif } // renderGlobal //----------------------------------------------------------------------------- @@ -260,6 +265,7 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt) */ void RaceGUI::drawScores() { +#ifndef SERVER_ONLY SoccerWorld* sw = dynamic_cast(World::getWorld()); int offset_y = 5; int offset_x = 5; @@ -301,6 +307,7 @@ void RaceGUI::drawScores() NULL,NULL,true); offset_x += position.LowerRightCorner.X + 30; } +#endif } // drawScores //----------------------------------------------------------------------------- @@ -370,6 +377,7 @@ void RaceGUI::drawGlobalTimer() */ void RaceGUI::drawGlobalMiniMap() { +#ifndef SERVER_ONLY World *world = World::getWorld(); // draw a map when arena has a navigation mesh. if ((world->getTrack()->isArena() || world->getTrack()->isSoccer()) && @@ -428,7 +436,7 @@ void RaceGUI::drawGlobalMiniMap() lower_y -(int)(draw_at.getY()-(m_minimap_player_size/2.5f))); draw2DImage(icon, position, source, NULL, NULL, true); } - +#endif } // drawGlobalMiniMap //----------------------------------------------------------------------------- @@ -444,6 +452,7 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, const core::recti &viewport, const core::vector2df &scaling) { +#ifndef SERVER_ONLY float min_ratio = std::min(scaling.X, scaling.Y); const int GAUGEWIDTH = 78; int gauge_width = (int)(GAUGEWIDTH*min_ratio); @@ -638,7 +647,7 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart, index, count-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN); } - +#endif } // drawEnergyMeter //----------------------------------------------------------------------------- @@ -738,6 +747,7 @@ void RaceGUI::drawSpeedEnergyRank(const AbstractKart* kart, const core::vector2df &scaling, float dt) { +#ifndef SERVER_ONLY float min_ratio = std::min(scaling.X, scaling.Y); const int SPEEDWIDTH = 128; int meter_width = (int)(SPEEDWIDTH*min_ratio); @@ -844,7 +854,7 @@ void RaceGUI::drawSpeedEnergyRank(const AbstractKart* kart, irr_driver->getVideoDriver()->setMaterial(m); draw2DVertexPrimitiveList(m_speed_bar_icon->getTexture(), vertices, count, index, count-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN); - +#endif } // drawSpeedEnergyRank //----------------------------------------------------------------------------- @@ -946,6 +956,7 @@ void RaceGUI::drawMultitouchSteering(const AbstractKart* kart, const core::recti &viewport, const core::vector2df &scaling) { +#ifndef SERVER_ONLY MultitouchDevice* device = input_manager->getDeviceManager()-> getMultitouchDevice(); @@ -1043,4 +1054,5 @@ void RaceGUI::drawMultitouchSteering(const AbstractKart* kart, } } } +#endif } // drawMultitouchSteering diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index 787caa048..3b28e7af1 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -305,6 +305,7 @@ void RaceGUIBase::drawPowerupIcons(const AbstractKart* kart, const core::recti &viewport, const core::vector2df &scaling) { +#ifndef SERVER_ONLY // If player doesn't have any powerups or has completed race, do nothing. const Powerup* powerup = kart->getPowerup(); if (powerup->getType() == PowerupManager::POWERUP_NOTHING @@ -354,6 +355,7 @@ void RaceGUIBase::drawPowerupIcons(const AbstractKart* kart, pos, video::SColor(255, 255, 255, 255)); font->setScale(1.0f); } +#endif } // drawPowerupIcons // ---------------------------------------------------------------------------- @@ -454,6 +456,7 @@ void RaceGUIBase::addMessage(const core::stringw &msg, */ void RaceGUIBase::drawGlobalMusicDescription() { +#ifndef SERVER_ONLY // show no music description when it's off if (!UserConfigParams::m_music) return; @@ -550,6 +553,7 @@ void RaceGUIBase::drawGlobalMusicDescription() draw2DImage(t, dest, source, NULL, NULL, true); +#endif } // drawGlobalMusicDescription //----------------------------------------------------------------------------- @@ -621,6 +625,7 @@ void RaceGUIBase::drawGlobalReadySetGo() */ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) { +#ifndef SERVER_ONLY // For now, don't draw player icons when in soccer mode const RaceManager::MinorRaceModeType minor_mode = race_manager->getMinorMode(); if(minor_mode == RaceManager::MINOR_MODE_SOCCER) @@ -934,6 +939,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) } } //next position +#endif } // drawGlobalPlayerIcons // ---------------------------------------------------------------------------- @@ -943,6 +949,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) */ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt) { +#ifndef SERVER_ONLY const AbstractKart *kart = camera->getKart(); if (kart->getBlockedByPlungerTime()<=0) { @@ -1029,4 +1036,5 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt) &viewport /* clip */, NULL /* color */, true /* alpha */ ); +#endif // !SERVER_ONLY } // drawPlungerInFace diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp index a41dc7502..bc5bcb4a1 100644 --- a/src/states_screens/race_gui_overworld.cpp +++ b/src/states_screens/race_gui_overworld.cpp @@ -25,6 +25,9 @@ #include "config/user_config.hpp" #include "graphics/camera.hpp" #include "graphics/2dutils.hpp" +#ifndef SERVER_ONLY +#include "graphics/glwrap.hpp" +#endif #include "graphics/irr_driver.hpp" #include "graphics/material_manager.hpp" #include "guiengine/engine.hpp" @@ -137,6 +140,7 @@ RaceGUIOverworld::~RaceGUIOverworld() */ void RaceGUIOverworld::renderGlobal(float dt) { +#ifndef SERVER_ONLY RaceGUIBase::renderGlobal(dt); cleanupMessages(dt); @@ -173,6 +177,7 @@ void RaceGUIOverworld::renderGlobal(float dt) //irr_driver->getVideoDriver()->enableMaterial2D(); m_is_first_render_call = false; +#endif } // renderGlobal //----------------------------------------------------------------------------- @@ -208,6 +213,7 @@ void RaceGUIOverworld::renderPlayerView(const Camera *camera, float dt) */ void RaceGUIOverworld::drawTrophyPoints() { +#ifndef SERVER_ONLY PlayerProfile *player = PlayerManager::getCurrentPlayer(); const int points = player->getPoints(); std::string s = StringUtils::toString(points); @@ -286,7 +292,7 @@ void RaceGUIOverworld::drawTrophyPoints() font->draw(sw.c_str(), pos, time_color, false, vcenter, NULL, true /* ignore RTL */); font->disableShadow(); - +#endif } // drawTrophyPoints //----------------------------------------------------------------------------- @@ -294,6 +300,7 @@ void RaceGUIOverworld::drawTrophyPoints() */ void RaceGUIOverworld::drawGlobalMiniMap() { +#ifndef SERVER_ONLY World *world = World::getWorld(); // arenas currently don't have a map. if(world->getTrack()->isArena() || world->getTrack()->isSoccer()) return; @@ -534,7 +541,7 @@ void RaceGUIOverworld::drawGlobalMiniMap() true, true /* vcenter */, NULL); } } - +#endif // SERVER_ONLY } // drawGlobalMiniMap //----------------------------------------------------------------------------- @@ -550,6 +557,7 @@ void RaceGUIOverworld::drawEnergyMeter(int x, int y, const AbstractKart *kart, const core::recti &viewport, const core::vector2df &scaling) { +#ifndef SERVER_ONLY float state = (float)(kart->getEnergy()) / kart->getKartProperties()->getNitroMax(); if (state < 0.0f) state = 0.0f; @@ -603,7 +611,7 @@ void RaceGUIOverworld::drawEnergyMeter(int x, int y, const AbstractKart *kart, &clip, NULL /* colors */, true /* alpha */); } - +#endif } // drawEnergyMeter //----------------------------------------------------------------------------- diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 109c695f1..97df2d6cb 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -45,7 +45,7 @@ #include "modes/soccer_world.hpp" #include "modes/world_with_rank.hpp" #include "network/protocol_manager.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" #include "race/highscores.hpp" #include "scriptengine/property_animator.hpp" #include "states_screens/feature_unlocked.hpp" @@ -341,10 +341,9 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, if (name == "middle") // Continue button (return to server lobby) { // Signal to the server that this client is back in the lobby now. - Protocol* protocol = - ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM); - ClientLobbyRoomProtocol* clrp = - static_cast(protocol); + Protocol* protocol = LobbyProtocol::get(); + ClientLobby* clrp = + dynamic_cast(protocol); if(clrp) clrp->doneWithResults(); backToLobby(); @@ -659,6 +658,7 @@ void RaceResultGUI::backToLobby() */ void RaceResultGUI::renderGlobal(float dt) { +#ifndef SERVER_ONLY bool isSoccerWorld = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER; m_timer += dt; @@ -830,6 +830,7 @@ void RaceResultGUI::backToLobby() { displayPostRaceInfo(); } +#endif } // renderGlobal //----------------------------------------------------------------------------- @@ -838,6 +839,7 @@ void RaceResultGUI::backToLobby() */ void RaceResultGUI::determineGPLayout() { +#ifndef SERVER_ONLY unsigned int num_karts = race_manager->getNumberOfKarts(); std::vector old_rank(num_karts, 0); for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) @@ -900,6 +902,7 @@ void RaceResultGUI::backToLobby() int p = race_manager->getKartScore(i); ri->m_new_overall_points = p; } // i < num_karts +#endif } // determineGPLayout //----------------------------------------------------------------------------- @@ -933,6 +936,7 @@ void RaceResultGUI::backToLobby() void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y, unsigned int n, bool display_points) { +#ifndef SERVER_ONLY RowInfo *ri = &(m_all_row_infos[n]); video::SColor color = ri->m_is_player_kart ? video::SColor(255, 255, 0, 0) @@ -1003,12 +1007,13 @@ void RaceResultGUI::backToLobby() m_font->draw(point_inc_string, dest_rect, color, false, false, NULL, true /* ignoreRTL */); } +#endif } // displayOneEntry //----------------------------------------------------------------------------- void RaceResultGUI::displaySoccerResults() { - +#ifndef SERVER_ONLY //Draw win text core::stringw result_text; static video::SColor color = video::SColor(255, 255, 255, 255); @@ -1177,6 +1182,7 @@ void RaceResultGUI::backToLobby() draw2DImage(scorer_icon, dest_rect, source_rect, NULL, NULL, true); } +#endif } //----------------------------------------------------------------------------- @@ -1324,6 +1330,7 @@ void RaceResultGUI::backToLobby() // ---------------------------------------------------------------------------- void RaceResultGUI::displayPostRaceInfo() { +#ifndef SERVER_ONLY // This happens in demo world if (!World::getWorld()) return; @@ -1441,8 +1448,9 @@ void RaceResultGUI::backToLobby() GUIEngine::getFont()->draw(best_lap_string, core::recti(x, current_y, 0, 0), white_color, false, false, nullptr, true); - } - } + } // if mode has laps + } // if not soccer mode +#endif } // ---------------------------------------------------------------------------- diff --git a/src/states_screens/tracks_screen.cpp b/src/states_screens/tracks_screen.cpp index cae841135..00d84e528 100644 --- a/src/states_screens/tracks_screen.cpp +++ b/src/states_screens/tracks_screen.cpp @@ -26,8 +26,7 @@ #include "guiengine/widgets/icon_button_widget.hpp" #include "io/file_manager.hpp" #include "network/network_player_profile.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/client_lobby_room_protocol.hpp" +#include "network/protocols/client_lobby.hpp" #include "network/stk_host.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/track_info_screen.hpp" @@ -90,10 +89,10 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, { if(STKHost::existHost()) { - Protocol* protocol = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_LOBBY_ROOM); - ClientLobbyRoomProtocol* clrp = - static_cast(protocol); + Protocol* protocol = LobbyProtocol::get(); + ClientLobby* clrp = + dynamic_cast(protocol); + assert(clrp); // server never shows the track screen. // FIXME SPLITSCREEN: we need to supply the global player id of the // player selecting the track here. For now ... just vote the same // track for each local player. diff --git a/src/tracks/check_cannon.cpp b/src/tracks/check_cannon.cpp index 34f30fcae..2fb3000c8 100644 --- a/src/tracks/check_cannon.cpp +++ b/src/tracks/check_cannon.cpp @@ -42,7 +42,7 @@ CheckCannon::CheckCannon(const XMLNode &node, unsigned int index) m_curve = new Ipo(*(node.getNode("curve")), /*fps*/25, /*reverse*/race_manager->getReverseTrack()); -#ifdef DEBUG +#if defined(DEBUG) && !defined(SERVER_ONLY) if(UserConfigParams::m_track_debug) { m_show_curve = new ShowCurve(0.5f, 0.5f); @@ -50,7 +50,7 @@ CheckCannon::CheckCannon(const XMLNode &node, unsigned int index) for(unsigned int i=0; iaddPoint(p[i]); } -#endif +#endif // DEBUG AND !SERVER_ONLY } // CheckCannon // ---------------------------------------------------------------------------- @@ -60,7 +60,7 @@ CheckCannon::CheckCannon(const XMLNode &node, unsigned int index) CheckCannon::~CheckCannon() { delete m_curve; -#ifdef DEBUG +#if defined(DEBUG) && !defined(SERVER_ONLY) if(UserConfigParams::m_track_debug) delete m_show_curve; #endif diff --git a/src/tracks/check_line.cpp b/src/tracks/check_line.cpp index 4b42c6687..bb9ace654 100644 --- a/src/tracks/check_line.cpp +++ b/src/tracks/check_line.cpp @@ -72,6 +72,7 @@ CheckLine::CheckLine(const XMLNode &node, unsigned int index) m_line.setLine(p1, p2); if(UserConfigParams::m_check_debug) { +#ifndef SERVER_ONLY video::SMaterial material; material.setFlag(video::EMF_BACK_FACE_CULLING, false); material.setFlag(video::EMF_LIGHTING, false); @@ -109,6 +110,7 @@ CheckLine::CheckLine(const XMLNode &node, unsigned int index) //mesh->setBoundingBox(buffer->getBoundingBox()); m_debug_node = irr_driver->addMesh(mesh, "checkdebug"); mesh->drop(); +#endif } else { @@ -150,7 +152,9 @@ void CheckLine::changeDebugColor(bool is_active) { vertices[i].Color = color; } +#ifndef SERVER_ONLY buffer->getMaterial().setTexture(0, getUnicolorTexture(color)); +#endif } // changeDebugColor diff --git a/src/tracks/graph.cpp b/src/tracks/graph.cpp index 04ad23449..5e4c36af2 100644 --- a/src/tracks/graph.cpp +++ b/src/tracks/graph.cpp @@ -101,6 +101,7 @@ void Graph::cleanupDebugMesh() void Graph::createMesh(bool show_invisible, bool enable_transparency, const video::SColor *track_color) { +#ifndef SERVER_ONLY // The debug track will not be lighted or culled. video::SMaterial m; m.BackfaceCulling = false; @@ -229,6 +230,7 @@ void Graph::createMesh(bool show_invisible, bool enable_transparency, delete[] ind; delete[] new_v; +#endif } // createMesh // ----------------------------------------------------------------------------- @@ -245,9 +247,9 @@ RenderTarget* Graph::makeMiniMap(const core::dimension2du &dimension, World::getWorld() ->setClearbackBufferColor(video::SColor(0, 255, 255, 255)); World::getWorld()->forceFogDisabled(true); - +#ifndef SERVER_ONLY m_render_target = irr_driver->createRenderTarget(dimension, name); - +#endif irr_driver->getSceneManager() ->setAmbientLight(video::SColor(255, 255, 255, 255)); diff --git a/src/tracks/model_definition_loader.cpp b/src/tracks/model_definition_loader.cpp index 737c8d697..852180e5f 100644 --- a/src/tracks/model_definition_loader.cpp +++ b/src/tracks/model_definition_loader.cpp @@ -35,7 +35,7 @@ using namespace irr; ModelDefinitionLoader::ModelDefinitionLoader(Track* track) { m_track = track; -} +} // ModelDefinitionLoader // ---------------------------------------------------------------------------- @@ -54,12 +54,13 @@ void ModelDefinitionLoader::addModelDefinition(const XMLNode* xml) xml->get("model", &model_name); m_lod_groups[lodgroup].push_back(ModelDefinition(xml, (int)lod_distance, model_name, false, skeletal_animation)); -} +} // addModelDefinition // ---------------------------------------------------------------------------- LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISceneNode* parent, RenderInfo* ri) { +#ifndef SERVER_ONLY scene::ISceneManager* sm = irr_driver->getSceneManager(); std::string groupname = ""; @@ -142,14 +143,17 @@ LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISc Log::warn("ModelDefinitionLoader", "LOD group '%s' is empty", groupname.c_str()); return NULL; } -} +#else + return NULL; +#endif +} // instanciateAsLOD // ---------------------------------------------------------------------------- void ModelDefinitionLoader::clear() { m_lod_groups.clear(); -} +} // clear // ---------------------------------------------------------------------------- @@ -162,7 +166,7 @@ scene::IMesh* ModelDefinitionLoader::getFirstMeshFor(const std::string& name) return irr_driver->getMesh(md[0].m_model_file); } return NULL; -} +} // getFirstMeshFor // ---------------------------------------------------------------------------- @@ -176,4 +180,4 @@ void ModelDefinitionLoader::cleanLibraryNodesAfterLoad() file_manager->popTextureSearchPath(); file_manager->popModelSearchPath(); } -} +} // cleanLibraryNodesAfterLoad diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 46fcd696c..ef0bed24f 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -280,11 +280,13 @@ void Track::cleanup() { Graph::destroy(); ItemManager::destroy(); +#ifndef SERVER_ONLY VAOManager::kill(); - ParticleKindManager::get()->cleanUpTrackSpecificGfx(); // Clear reminder of transformed textures resetTextureTable(); +#endif + // Clear reminder of the link between textures and file names. irr_driver->clearTexturesFileName(); @@ -320,16 +322,20 @@ void Track::cleanup() m_object_physics_only_nodes.clear(); irr_driver->removeNode(m_sun); +#ifndef SERVER_ONLY if (CVS->isGLSL()) m_sun->drop(); +#endif delete m_track_mesh; m_track_mesh = NULL; delete m_gfx_effect_mesh; m_gfx_effect_mesh = NULL; +#ifndef SERVER_ONLY if (CVS->isGLSL()) irr_driver->cleanSunInterposer(); +#endif // The m_all_cached_mesh contains each mesh loaded from a file, which @@ -787,12 +793,16 @@ void Track::createPhysicsModel(unsigned int main_track_count) } // Color +#ifndef SERVER_ONLY mb->getMaterial().setTexture(0, getUnicolorTexture(video::SColor(255, 255, 105, 180))); +#endif irr_driver->grabAllTextures(mesh); // Gloss +#ifndef SERVER_ONLY mb->getMaterial().setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0))); // Colorization mask mb->getMaterial().setTexture(2, getUnicolorTexture(video::SColor(0, 0, 0, 0))); +#endif } else irr_driver->removeNode(m_static_physics_only_nodes[i]); @@ -1029,6 +1039,7 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) void Track::loadMinimap() { +#ifndef SERVER_ONLY //Check whether the hardware can do nonsquare or // non power-of-two textures video::IVideoDriver* const video_driver = irr_driver->getVideoDriver(); @@ -1055,6 +1066,7 @@ void Track::loadMinimap() m_minimap_y_scale = float(m_mini_map_size.Height) / float(mini_map_texture_size.Height); else m_minimap_y_scale = 0; +#endif } // loadMinimap // ---------------------------------------------------------------------------- @@ -1122,10 +1134,13 @@ bool Track::loadMainTrack(const XMLNode &root) scene::CBatchingMesh *merged_mesh = new scene::CBatchingMesh(); merged_mesh->addMesh(mesh); merged_mesh->finalize(); - +#ifndef SERVER_ONLY scene::IMesh* tangent_mesh = MeshTools::createMeshWithTangents(merged_mesh, &MeshTools::isNormalMap); adjustForFog(tangent_mesh, NULL); +#else + scene::IMesh* tangent_mesh = merged_mesh; +#endif // The merged mesh is grabbed by the octtree, so we don't need // to keep a reference to it. @@ -1243,8 +1258,9 @@ bool Track::loadMainTrack(const XMLNode &root) full_path.c_str()); continue; } - +#ifndef SERVER_ONLY a_mesh = MeshTools::createMeshWithTangents(a_mesh, &MeshTools::isNormalMap); +#endif // The meshes loaded here are in irrlicht's mesh cache. So we // have to keep track of them in order to properly remove them @@ -1753,7 +1769,8 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) // It's important to execute this BEFORE the code that creates the skycube, // otherwise the skycube node could be modified to have fog enabled, which // we don't want - if (m_use_fog && Camera::getDefaultCameraType()!=Camera::CM_TYPE_DEBUG && +#ifndef SERVER_ONLY + if (m_use_fog && Camera::getDefaultCameraType()!=Camera::CM_TYPE_DEBUG && !CVS->isGLSL()) { /* NOTE: if LINEAR type, density does not matter, if EXP or EXP2, start @@ -1763,6 +1780,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) m_fog_start, m_fog_end, 1.0f); } +#endif // Enable for for all track nodes if fog is used const unsigned int count = (int)m_all_nodes.size(); @@ -1831,6 +1849,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) const video::SColorf tmpf(m_sun_diffuse_color); m_sun = irr_driver->addLight(m_sun_position, 0., 0., tmpf.r, tmpf.g, tmpf.b, true); +#ifndef SERVER_ONLY if (!CVS->isGLSL()) { scene::ILightSceneNode *sun = (scene::ILightSceneNode *) m_sun; @@ -1853,6 +1872,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) irr_driver->createSunInterposer(); m_sun->grab(); } +#endif createPhysicsModel(main_track_count); diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 2dbfc4b6c..fa70762ad 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -363,6 +363,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( throw std::runtime_error("Model '" + model_name + "' cannot be found"); } +#ifndef SERVER_ONLY if (!animated) { m_mesh = MeshTools::createMeshWithTangents(m_mesh, @@ -378,6 +379,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( &MeshTools::isNormalMap); } } +#endif init(&xml_node, parent, enabled); } // TrackObjectPresentationMesh @@ -416,6 +418,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( m_model_file = model_file; file_manager->pushTextureSearchPath(StringUtils::getPath(model_file)); +#ifndef SERVER_ONLY if (file_manager->fileExists(model_file)) { if (animated) @@ -435,6 +438,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( irr_driver->getMesh(model_file), &MeshTools::isNormalMap); } } +#endif if (!m_mesh) { @@ -534,9 +538,11 @@ void TrackObjectPresentationMesh::init(const XMLNode* xml_node, m_node = irr_driver->addMesh(m_mesh, m_model_file, parent, m_render_info); +#ifndef SERVER_ONLY STKMeshSceneNode* stkmesh = dynamic_cast(m_node); if (displacing && stkmesh != NULL) stkmesh->setIsDisplacement(displacing); +#endif m_frame_start = 0; m_frame_end = 0; @@ -857,7 +863,6 @@ TrackObjectPresentationParticles::TrackObjectPresentationParticles( { m_emitter = NULL; m_lod_emitter_node = NULL; - std::string path; xml_node.get("kind", &path); @@ -871,6 +876,7 @@ TrackObjectPresentationParticles::TrackObjectPresentationParticles( m_delayed_stop = false; m_delayed_stop_time = 0.0; +#ifndef SERVER_ONLY try { ParticleKind* kind = ParticleKindManager::get()->getParticles(path); @@ -907,6 +913,7 @@ TrackObjectPresentationParticles::TrackObjectPresentationParticles( Log::warn ("Track", "Could not load particles '%s'; cause :\n %s", path.c_str(), e.what()); } +#endif } // TrackObjectPresentationParticles // ---------------------------------------------------------------------------- @@ -945,20 +952,24 @@ void TrackObjectPresentationParticles::update(float dt) // ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::triggerParticles() { +#ifndef SERVER_ONLY if (m_emitter != NULL) { m_emitter->setCreationRateAbsolute(1.0f); m_emitter->setParticleType(m_emitter->getParticlesInfo()); } +#endif } // triggerParticles // ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::stop() { +#ifndef SERVER_ONLY if (m_emitter != NULL) { m_emitter->setCreationRateAbsolute(0.0f); m_emitter->clearParticles(); } +#endif } // ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::stopIn(double delay) @@ -969,12 +980,15 @@ void TrackObjectPresentationParticles::stopIn(double delay) // ---------------------------------------------------------------------------- void TrackObjectPresentationParticles::setRate(float rate) { +#ifndef SERVER_ONLY if (m_emitter != NULL) { m_emitter->setCreationRateAbsolute(rate); m_emitter->setParticleType(m_emitter->getParticlesInfo()); } -} +#endif +} // setRate + // ---------------------------------------------------------------------------- TrackObjectPresentationLight::TrackObjectPresentationLight( const XMLNode& xml_node, @@ -990,7 +1004,7 @@ TrackObjectPresentationLight::TrackObjectPresentationLight( m_distance = 20.f * m_energy; xml_node.get("distance", &m_distance); - +#ifndef SERVER_ONLY if (CVS->isGLSL()) { m_node = irr_driver->addLight(m_init_xyz, m_energy, m_distance, @@ -998,6 +1012,7 @@ TrackObjectPresentationLight::TrackObjectPresentationLight( parent); } else +#endif { m_node = NULL; // lights require shaders to work } diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index a8d4dd035..f9d82f23d 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -234,8 +234,10 @@ bool handleContextMenuAction(s32 cmd_id) switch(cmd_id) { case DEBUG_GRAPHICS_RELOAD_SHADERS: - Log::info("Debug", "Reloading shaders..."); +#ifndef SERVER_ONLY + Log::info("Debug", "Reloading shaders..."); ShaderBase::updateShaders(); +#endif break; case DEBUG_GRAPHICS_RESET: if (physics) diff --git a/src/utils/log.cpp b/src/utils/log.cpp index f77f0bcfc..e5d39167e 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -140,11 +140,11 @@ void Log::printMessage(int level, const char *component, const char *format, android_LogPriority alp; switch (level) { - // STK is using the levels slightly different from android - // (debug lowest, verbose above it; while android reverses - // this order. So to get the same behaviour (e.g. filter - // out debug message, but still get verbose, we swap - // the order here. + // STK is using the levels slightly different from android + // (debug lowest, verbose above it; while android reverses + // this order. So to get the same behaviour (e.g. filter + // out debug message, but still get verbose, we swap + // the order here. case LL_VERBOSE: alp = ANDROID_LOG_DEBUG; break; case LL_DEBUG: alp = ANDROID_LOG_VERBOSE; break; case LL_INFO: alp = ANDROID_LOG_INFO; break; @@ -153,8 +153,8 @@ void Log::printMessage(int level, const char *component, const char *format, case LL_FATAL: alp = ANDROID_LOG_FATAL; break; default: alp = ANDROID_LOG_FATAL; } - __android_log_vprint(alp, "SuperTuxKart", format, args); -#else +#endif + static const char *names[] = {"debug", "verbose ", "info ", "warn ", "error ", "fatal "}; @@ -178,8 +178,12 @@ void Log::printMessage(int level, const char *component, const char *format, va_copy(out, args); setTerminalColor((LogLevel)level); + #ifdef ANDROID + __android_log_vprint(alp, "SuperTuxKart", format, out); + #else printf("[%s] %s: ", names[level], component); vprintf(format, out); + #endif resetTerminalColor(); // this prints a \n va_end(out); @@ -225,8 +229,6 @@ void Log::printMessage(int level, const char *component, const char *format, MessageBoxA(NULL, message.c_str(), "SuperTuxKart - Fatal error", MB_OK); } #endif - -#endif } // printMessage diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index 98de8cd9a..bbcfb54ad 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -17,11 +17,13 @@ #include "profiler.hpp" #include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" #include "graphics/2dutils.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/engine.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/scalable_font.hpp" +#include "io/file_manager.hpp" #include "utils/vs.hpp" #include @@ -266,6 +268,7 @@ void Profiler::synchronizeFrame() /// Draw the markers void Profiler::draw() { +#ifndef SERVER_ONLY PROFILER_PUSH_CPU_MARKER("ProfilerDraw", 0xFF, 0xFF, 0x00); video::IVideoDriver* driver = irr_driver->getVideoDriver(); std::stack hovered_markers; @@ -372,7 +375,9 @@ void Profiler::draw() unsigned int gpu_timers[Q_LAST]; for (unsigned i = 0; i < Q_LAST; i++) { +#ifndef SERVER_ONLY gpu_timers[i] = irr_driver->getGPUTimer(i).elapsedTimeus(); +#endif total += gpu_timers[i]; } @@ -466,6 +471,7 @@ void Profiler::draw() } PROFILER_POP_CPU_MARKER(); +#endif } //----------------------------------------------------------------------------- @@ -506,6 +512,7 @@ void Profiler::onClick(const core::vector2di& mouse_pos) /// Helper to draw a white background void Profiler::drawBackground() { +#ifndef SERVER_ONLY video::IVideoDriver* driver = irr_driver->getVideoDriver(); const core::dimension2d& screen_size = driver->getScreenSize(); @@ -516,4 +523,5 @@ void Profiler::drawBackground() video::SColor color(0x88, 0xFF, 0xFF, 0xFF); GL32_draw2DRectangle(color, background_rect); +#endif }