diff --git a/CMakeLists.txt b/CMakeLists.txt index 0df8279f1..54b133ac3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,8 +54,8 @@ ENDIF() CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(RyzomCore CXX C) SET(NL_VERSION_MAJOR 1) -SET(NL_VERSION_MINOR 0) -SET(NL_VERSION_PATCH 2) +SET(NL_VERSION_MINOR 1) +SET(NL_VERSION_PATCH 0 CACHE STRING "Patch version") SET(YEAR "2001-${CURRENT_YEAR}") SET(AUTHOR "Winch Gate and The Ryzom Core Community") diff --git a/nel/include/nel/gui/lua_helper.h b/nel/include/nel/gui/lua_helper.h index da5c33e6a..8a0f985a6 100644 --- a/nel/include/nel/gui/lua_helper.h +++ b/nel/include/nel/gui/lua_helper.h @@ -379,6 +379,10 @@ namespace NLGUI TSmallScriptCache _SmallScriptCache; static const char * _NELSmallScriptTableName; +#ifdef _WIN32 + HMODULE m_LuaSocket; +#endif + private: // this object isn't intended to be copied CLuaState(const CLuaState &/* other */):NLMISC::CRefCount() { nlassert(0); } diff --git a/nel/include/nel/gui/lua_helper_inline.h b/nel/include/nel/gui/lua_helper_inline.h index 0d380bbf1..5dbc3cef4 100644 --- a/nel/include/nel/gui/lua_helper_inline.h +++ b/nel/include/nel/gui/lua_helper_inline.h @@ -263,8 +263,8 @@ inline lua_Integer CLuaState::toInteger(int index) if (!isnum) { lua_Number d = lua_tonumber(_State, index); - nlwarning("Lua: Unable to convert Lua number %lf to integer", d); res = (lua_Integer)d; + nlwarning("Lua: Converting lua_Number %lf to lua_Integer %i", d, (int)res); } return res; #else diff --git a/nel/include/nel/misc/debug.h b/nel/include/nel/misc/debug.h index a8c23eced..1d533c149 100644 --- a/nel/include/nel/misc/debug.h +++ b/nel/include/nel/misc/debug.h @@ -89,6 +89,9 @@ void createDebug (const char *logPath = NULL, bool logInFile = true, bool eraseL /// Do not call this, unless you know what you're trying to do (it kills debug)! void destroyDebug(); +/// Attach exception handler, for new threads and fibers +void attachExceptionHandler(); + // call this if you want to change the dir of the log.log file void changeLogDirectory(const std::string &dir); @@ -352,7 +355,7 @@ void setCrashAlreadyReported(bool state); * Same as nlassertex(false,exp); */ -// removed because we always check assert (even in release mode) #if defined (NL_OS_WINDOWS) && defined (NL_DEBUG) +#if defined(NL_DEBUG) /* Debug break is only useful in debug builds */ #if defined(NL_OS_WINDOWS) #define NLMISC_BREAKPOINT __debugbreak() #elif defined(NL_OS_UNIX) && defined(NL_COMP_GCC) @@ -360,6 +363,9 @@ void setCrashAlreadyReported(bool state); #else #define NLMISC_BREAKPOINT abort() #endif +#else +#define NLMISC_BREAKPOINT do { } while (0) +#endif // Internal, don't use it (make smaller assert code) extern bool _assert_stop(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp); diff --git a/nel/include/nel/net/unified_network.h b/nel/include/nel/net/unified_network.h index d380427b6..df735a740 100644 --- a/nel/include/nel/net/unified_network.h +++ b/nel/include/nel/net/unified_network.h @@ -662,6 +662,7 @@ private: std::vector _UpUniCallback; TNameMappedCallback _DownCallbacks; std::vector _DownUniCallback; + std::set> _NotifiedUpCallbacks; /// Recording state CCallbackNetBase::TRecordingState _RecordingState; diff --git a/nel/include/nel/sound/driver/sound_driver.h b/nel/include/nel/sound/driver/sound_driver.h index 1fba9c887..9c758487a 100644 --- a/nel/include/nel/sound/driver/sound_driver.h +++ b/nel/include/nel/sound/driver/sound_driver.h @@ -191,7 +191,7 @@ public: /// Create a native music channel, only supported by the FMod driver. virtual IMusicChannel *createMusicChannel() { return NULL; } /** Get music info. Returns false if the song is not found or the function is not implemented. - * \param filepath path to file, CPath::lookup done by driver + * \param filepath full path to file * \param artist returns the song artist (empty if not available) * \param title returns the title (empty if not available) */ diff --git a/nel/include/nel/sound/music_channel_fader.h b/nel/include/nel/sound/music_channel_fader.h index 6bb5677f9..577d23949 100644 --- a/nel/include/nel/sound/music_channel_fader.h +++ b/nel/include/nel/sound/music_channel_fader.h @@ -108,7 +108,7 @@ public: bool play(const std::string &filepath, uint xFadeTime = 0, bool async = true, bool loop = true); /// Stop the music previously loaded and played (the Memory is also freed) - void stop(uint xFadeTime = 0); + bool stop(uint xFadeTime = 0); /// Pause the music previously loaded and played (the Memory is not freed) void pause(); diff --git a/nel/include/nel/sound/stream_file_source.h b/nel/include/nel/sound/stream_file_source.h index 4069a2f58..c8cf91cf5 100644 --- a/nel/include/nel/sound/stream_file_source.h +++ b/nel/include/nel/sound/stream_file_source.h @@ -96,6 +96,8 @@ private: IAudioDecoder *m_AudioDecoder; + std::string m_LookupPath; + bool m_Paused; bool m_DecodingEnded; diff --git a/nel/include/nel/web/http_client_curl.h b/nel/include/nel/web/http_client_curl.h index 77cf335ca..e130cd768 100644 --- a/nel/include/nel/web/http_client_curl.h +++ b/nel/include/nel/web/http_client_curl.h @@ -34,7 +34,7 @@ class CCurlHttpClient public: /// Constructor - CCurlHttpClient() {} + CCurlHttpClient() : _CurlStruct(NULL) {} /// Connect to an http server (string by val is intended). If you specify a whole URL, an attempt will be made to determine the server. bool connect(const std::string &server); diff --git a/nel/src/3d/driver/direct3d/driver_direct3d.cpp b/nel/src/3d/driver/direct3d/driver_direct3d.cpp index 4f586ccd2..d91fec632 100644 --- a/nel/src/3d/driver/direct3d/driver_direct3d.cpp +++ b/nel/src/3d/driver/direct3d/driver_direct3d.cpp @@ -3830,9 +3830,15 @@ void CDriverD3D::CLightState::apply(CDriverD3D *driver) void CDriverD3D::CRenderTargetState::apply(CDriverD3D *driver) { H_AUTO_D3D(CDriverD3D_CRenderTargetState); - driver->_DeviceInterface->SetRenderTarget (0, Target); + nlassert(TargetOwned); // Can only apply once! + driver->_DeviceInterface->SetRenderTarget(0, Target); driver->setupViewport(driver->_Viewport); driver->setupScissor(driver->_Scissor); + if (TargetOwned) + { + Target->Release(); + TargetOwned = false; + } } // *************************************************************************** diff --git a/nel/src/3d/driver/direct3d/driver_direct3d.h b/nel/src/3d/driver/direct3d/driver_direct3d.h index b74fb0fa7..3c2dc3596 100644 --- a/nel/src/3d/driver/direct3d/driver_direct3d.h +++ b/nel/src/3d/driver/direct3d/driver_direct3d.h @@ -1546,11 +1546,13 @@ public: Texture = NULL; Level = 0; CubeFace = 0; + TargetOwned = false; } IDirect3DSurface9 *Target; ITexture *Texture; uint8 Level; uint8 CubeFace; + bool TargetOwned; virtual void apply(CDriverD3D *driver); }; @@ -2076,10 +2078,17 @@ public: NL_D3D_CACHE_TEST(CacheTest_RenderTarget, _RenderTarget.Target != target) #endif // NL_D3D_USE_RENDER_STATE_CACHE { + if (_RenderTarget.TargetOwned) + { + nlassert(_RenderTarget.Target); + _RenderTarget.Target->Release(); + } _RenderTarget.Target = target; _RenderTarget.Texture = texture; _RenderTarget.Level = level; _RenderTarget.CubeFace = cubeFace; + _RenderTarget.TargetOwned = target; + target->AddRef(); touchRenderVariable (&_RenderTarget); diff --git a/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp b/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp index f902e9fb0..2285688d4 100644 --- a/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp +++ b/nel/src/3d/driver/direct3d/driver_direct3d_material.cpp @@ -706,9 +706,13 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) // Set the texture states if (text || (stage == 0)) { - // Doesn't use a pixel shader ? Set the textures stages - if (pShader->PixelShader == NULL) + if (matShader == CMaterial::Program) { + // Do nothing for user pixel shader + } + else if (!pShader->PixelShader) + { + // Doesn't use a pixel shader ? Set the textures stages if (pShader->RGBPipe[stage]) { setTextureState (stage, D3DTSS_COLOROP, pShader->ColorOp[stage]); @@ -1145,7 +1149,7 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) } break; - case CMaterial::Cloud: + case CMaterial::Cloud: { H_AUTO_D3D(CDriverD3D_setupMaterial_setupCloudShader) activeShader (&_ShaderCloud); @@ -1167,7 +1171,7 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) return false; } break; - case CMaterial::Water: + case CMaterial::Water: { H_AUTO_D3D(CDriverD3D_setupMaterial_setupWaterShader) activeShader(mat.getTexture(3) ? &_ShaderWaterDiffuse : &_ShaderWaterNoDiffuse); @@ -1296,7 +1300,14 @@ bool CDriverD3D::setupMaterial(CMaterial &mat) } } } - // CMaterial::Water + break; // CMaterial::Water + case CMaterial::Program: + { + H_AUTO_D3D(CDriverD3D_setupMaterial_setupProgramshader) + // No material shader + activeShader(NULL); + } + break; } // New material setuped diff --git a/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp b/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp index f45663f1b..15dcb7768 100644 --- a/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp +++ b/nel/src/3d/driver/direct3d/driver_direct3d_texture.cpp @@ -1084,6 +1084,7 @@ void CDriverD3D::swapTextureHandle(ITexture &tex0, ITexture &tex1) swap(t0->Height, t1->Height); swap(t0->SrcCompressed, t1->SrcCompressed); swap(t0->IsCube, t1->IsCube); + swap(t0->RenderTarget, t1->RenderTarget); swap(t0->Levels, t1->Levels); swap(t0->FirstMipMap, t1->FirstMipMap); swap(t0->TextureMemory, t1->TextureMemory); diff --git a/nel/src/3d/driver/opengl/driver_opengl_extension.cpp b/nel/src/3d/driver/opengl/driver_opengl_extension.cpp index c81ab9e1e..0b8c4a458 100644 --- a/nel/src/3d/driver/opengl/driver_opengl_extension.cpp +++ b/nel/src/3d/driver/opengl/driver_opengl_extension.cpp @@ -1584,6 +1584,14 @@ void registerGlExtensions(CGlExtensions &ext) { H_AUTO_OGL(registerGlExtensions); +#ifdef NL_OS_MAC + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx == NULL) + { + nlerror("No OpenGL context set"); + } +#endif + // OpenGL 1.2 ?? const char *nglVersion = (const char *)glGetString (GL_VERSION); diff --git a/nel/src/3d/driver/opengl/driver_opengl_window.cpp b/nel/src/3d/driver/opengl/driver_opengl_window.cpp index 293cb28bb..f04ad304e 100644 --- a/nel/src/3d/driver/opengl/driver_opengl_window.cpp +++ b/nel/src/3d/driver/opengl/driver_opengl_window.cpp @@ -1072,6 +1072,9 @@ bool CDriverGL::setDisplay(nlWindow wnd, const GfxMode &mode, bool show, bool re [_ctx flushBuffer]; [_glView display]; + // Set context as thread context + CGLSetCurrentContext((CGLContextObj)[_ctx CGLContextObj]); + _EventEmitter.init(this, _glView, _DestroyWindow); #elif defined(NL_OS_UNIX) diff --git a/nel/src/3d/fxaa.cpp b/nel/src/3d/fxaa.cpp index 255f0234d..6478abf8e 100644 --- a/nel/src/3d/fxaa.cpp +++ b/nel/src/3d/fxaa.cpp @@ -246,6 +246,7 @@ void CFXAA::applyEffect() // create render target CTextureUser *otherRenderTarget = m_Driver->getRenderTargetManager().getRenderTarget(width, height, mode2D); + nlassert(otherRenderTarget); // swap render target CTextureUser texNull; diff --git a/nel/src/3d/lod_character_manager.cpp b/nel/src/3d/lod_character_manager.cpp index 92dee846a..f5d6a23c5 100644 --- a/nel/src/3d/lod_character_manager.cpp +++ b/nel/src/3d/lod_character_manager.cpp @@ -979,6 +979,9 @@ void CLodCharacterManager::addTextureCompute(CLodCharacterInstance &instance, // get lookup ptr. nlassert(lodTexture.Texture.size()==NL3D_CLOD_TEXT_SIZE); + if (lodTexture.Texture.size() < NL3D_CLOD_TEXT_SIZE) + return; + const CLodCharacterTexture::CTUVQ *lookUpPtr= &lodTexture.Texture[0]; // apply the lodTexture, taking only better quality (ie nearer 0) diff --git a/nel/src/gui/lua_helper.cpp b/nel/src/gui/lua_helper.cpp index d2b6a68d3..a07ba3b71 100644 --- a/nel/src/gui/lua_helper.cpp +++ b/nel/src/gui/lua_helper.cpp @@ -216,16 +216,55 @@ namespace NLGUI // *** Load base libs { CLuaStackChecker lsc(this); - #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501 +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501 luaL_openlibs(_State); - #else +#else luaopen_base (_State); luaopen_table (_State); luaopen_io (_State); luaopen_string (_State); luaopen_math (_State); luaopen_debug (_State); - #endif +#endif + +#ifdef _WIN32 + // Lua socket library for MobDebug, optional + if (NLMISC::CFile::fileExists("socket\\core.dll")) + { + // Load socket\core.dll dynamically + m_LuaSocket = LoadLibraryW(L"socket\\core.dll"); + if (!m_LuaSocket) + { + nlwarning("Lua socket library found, but failed to load"); + } + else + { + void *luaopen_socket_core = (void *)GetProcAddress(m_LuaSocket, "luaopen_socket_core"); + if (!luaopen_socket_core) + { + nlwarning("Lua socket library loaded, but `luaopen_socket_core` not found"); + FreeLibrary(m_LuaSocket); + m_LuaSocket = NULL; + } + else + { + // preload['socket.core'] = luaopen_socket_core +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501 + lua_getglobal(_State, "package"); + lua_getfield(_State, -1, "preload"); + lua_pushcfunction(_State, (lua_CFunction)luaopen_socket_core); + lua_setfield(_State, -2, "socket.core"); + lua_pop(_State, 2); + nlinfo("Lua socket library preloaded"); +#endif + } + } + } + else + { + m_LuaSocket = NULL; + } +#endif // open are buggy???? clear(); @@ -313,6 +352,14 @@ namespace NLGUI // Clear Small Script Cache _SmallScriptPool= 0; _SmallScriptCache.clear(); + +#ifdef _WIN32 + if (m_LuaSocket) + { + FreeLibrary(m_LuaSocket); + m_LuaSocket = NULL; + } +#endif } // *************************************************************************** @@ -464,7 +511,23 @@ namespace NLGUI // execute the script text, with dbgSrc==filename (use @ for lua internal purpose) - executeScriptInternal(script, string("@") + CFile::getFilename(pathName)); +#ifdef _WIN32 + // Paths need to be correct for debugging to work + std::string pathNameStandardized = pathName; + if (pathNameStandardized.size() > 1) + { + if (pathNameStandardized[1] == ':' && pathNameStandardized[0] >= 'a' && pathNameStandardized[0] <= 'z') + pathNameStandardized[0] -= 'a' - 'A'; + for (ptrdiff_t i = 0; i < (ptrdiff_t)pathNameStandardized.size(); ++i) + { + if (pathNameStandardized[i] == '/') + pathNameStandardized[i] = '\\'; + } + } +#else + const std::string &pathNameStandardized = pathName; +#endif + executeScriptInternal(script, string("@") + pathNameStandardized); return true; } diff --git a/nel/src/misc/co_task.cpp b/nel/src/misc/co_task.cpp index 524cc69c6..4548fbe86 100644 --- a/nel/src/misc/co_task.cpp +++ b/nel/src/misc/co_task.cpp @@ -143,6 +143,9 @@ namespace NLMISC NL_CT_DEBUG("CoTask : task %p start func called", task); + // Attach exception handler + attachExceptionHandler(); + try { // run the task @@ -151,6 +154,7 @@ namespace NLMISC catch(...) { nlwarning("CCoTask::startFunc : the task has generated an unhandled exeption and will terminate"); + NLMISC_BREAKPOINT; } task->_Finished = true; diff --git a/nel/src/misc/debug.cpp b/nel/src/misc/debug.cpp index cc3203a14..1f7cf38db 100644 --- a/nel/src/misc/debug.cpp +++ b/nel/src/misc/debug.cpp @@ -1157,6 +1157,15 @@ void destroyDebug() } } +void attachExceptionHandler() +{ +#ifndef NL_COMP_MINGW +# ifdef NL_OS_WINDOWS + _set_se_translator(exceptionTranslator); +# endif // NL_OS_WINDOWS +#endif //!NL_COMP_MINGW +} + void createDebug (const char *logPath, bool logInFile, bool eraseLastLog) { // Do some basic compiler time check on type size diff --git a/nel/src/misc/system_info.cpp b/nel/src/misc/system_info.cpp index 1f5039de5..5dc70182c 100644 --- a/nel/src/misc/system_info.cpp +++ b/nel/src/misc/system_info.cpp @@ -179,7 +179,6 @@ #else # include # include -# include # include # include # include diff --git a/nel/src/misc/win_thread.cpp b/nel/src/misc/win_thread.cpp index a75b2165f..0de191d55 100644 --- a/nel/src/misc/win_thread.cpp +++ b/nel/src/misc/win_thread.cpp @@ -67,6 +67,9 @@ static unsigned long __stdcall ProxyFunc (void *arg) // Set the thread pointer in TLS memory nlverify (TlsSetValue (TLSThreadPointer, (void*)parent) != 0); + // Attach exception handler + attachExceptionHandler(); + // Run the thread parent->Runnable->run(); diff --git a/nel/src/net/unified_network.cpp b/nel/src/net/unified_network.cpp index 5a6034e18..ca3ef37d7 100644 --- a/nel/src/net/unified_network.cpp +++ b/nel/src/net/unified_network.cpp @@ -2090,6 +2090,14 @@ void CUnifiedNetwork::addNetworkAssociation (const string &networkName, uint8 ni void CUnifiedNetwork::callServiceUpCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback) { + std::pair pss = std::make_pair(serviceName, sid); + if (_NotifiedUpCallbacks.find(pss) != _NotifiedUpCallbacks.end()) + { + nlwarning("HNETL5: Attempt to call service UP callback twice for '%s', ignored!", serviceName.c_str()); + return; + } + _NotifiedUpCallbacks.insert(pss); + // now we warn the user CUnifiedNetwork::TNameMappedCallback::iterator it = _UpCallbacks.find(serviceName); if (it != _UpCallbacks.end()) @@ -2119,6 +2127,14 @@ void CUnifiedNetwork::callServiceUpCallback (const std::string &serviceName, TSe void CUnifiedNetwork::callServiceDownCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback) { + std::pair pss = std::make_pair(serviceName, sid); + if (_NotifiedUpCallbacks.find(pss) == _NotifiedUpCallbacks.end()) + { + nlwarning("HNETL5: Attempt to call service DOWN callback twice for '%s', ignored!", serviceName.c_str()); + return; + } + _NotifiedUpCallbacks.erase(pss); + // now we warn the user CUnifiedNetwork::TNameMappedCallback::iterator it = _DownCallbacks.find(serviceName); if (it != _DownCallbacks.end()) diff --git a/nel/src/pacs/move_container.cpp b/nel/src/pacs/move_container.cpp index 7c346aed4..099f46839 100644 --- a/nel/src/pacs/move_container.cpp +++ b/nel/src/pacs/move_container.cpp @@ -418,13 +418,13 @@ void CMoveContainer::updateCells (CMovePrimitive *primitive, uint8 worldImage) /* // Check BB width not too large if (wI->getBBXMax() - wI->getBBXMin() > _CellWidth) { - nlwarning ("Primitives have moved more than a cell."); + nlwarning ("Primitives have moved more than a cell, width: %f.", (float)(wI->getBBXMax() - wI->getBBXMin())); } // Check BB height not too large if (wI->getBBYMax() - wI->getBBYMin() > _CellHeight) { - nlwarning ("Primitives have moved more than a cell."); + nlwarning ("Primitives have moved more than a cell, height: %f.", (float)(wI->getBBYMax() - wI->getBBYMin())); } */ #endif diff --git a/nel/src/sound/audio_decoder.cpp b/nel/src/sound/audio_decoder.cpp index ac7745721..db87bd990 100644 --- a/nel/src/sound/audio_decoder.cpp +++ b/nel/src/sound/audio_decoder.cpp @@ -56,18 +56,12 @@ IAudioDecoder::~IAudioDecoder() IAudioDecoder *IAudioDecoder::createAudioDecoder(const std::string &filepath, bool async, bool loop) { - std::string lookup = CPath::lookup(filepath, false); - if (lookup.empty()) - { - nlwarning("Music file %s does not exist!", filepath.c_str()); - return NULL; - } std::string type = CFile::getExtension(filepath); CIFile *ifile = new CIFile(); ifile->setCacheFileOnOpen(!async); ifile->allowBNPCacheFileOnOpen(!async); - ifile->open(lookup); + ifile->open(filepath); IAudioDecoder *mb = createAudioDecoder(type, ifile, loop); @@ -116,10 +110,9 @@ IAudioDecoder *IAudioDecoder::createAudioDecoder(const std::string &type, NLMISC bool IAudioDecoder::getInfo(const std::string &filepath, std::string &artist, std::string &title, float &length) { - std::string lookup = CPath::lookup(filepath, false); - if (lookup.empty()) + if (filepath.empty() || !CFile::fileExists(filepath)) { - nlwarning("Music file %s does not exist!", filepath.c_str()); + nlwarning("Music file '%s' does not exist!", filepath.c_str()); return false; } @@ -127,7 +120,7 @@ bool IAudioDecoder::getInfo(const std::string &filepath, std::string &artist, st CIFile ifile; ifile.setCacheFileOnOpen(false); ifile.allowBNPCacheFileOnOpen(false); - if (ifile.open(lookup)) + if (ifile.open(filepath)) return CAudioDecoderFfmpeg::getInfo(&ifile, artist, title, length); #else std::string type = CFile::getExtension(filepath); @@ -138,7 +131,7 @@ bool IAudioDecoder::getInfo(const std::string &filepath, std::string &artist, st CIFile ifile; ifile.setCacheFileOnOpen(false); ifile.allowBNPCacheFileOnOpen(false); - if (ifile.open(lookup)) + if (ifile.open(filepath)) return CAudioDecoderVorbis::getInfo(&ifile, artist, title, length); nlwarning("Unable to open: '%s'", filepath.c_str()); @@ -149,7 +142,7 @@ bool IAudioDecoder::getInfo(const std::string &filepath, std::string &artist, st CIFile ifile; ifile.setCacheFileOnOpen(false); ifile.allowBNPCacheFileOnOpen(false); - if (ifile.open(lookup)) + if (ifile.open(filepath)) return CAudioDecoderMP3::getInfo(&ifile, artist, title, length); nlwarning("Unable to open: '%s'", filepath.c_str()); diff --git a/nel/src/sound/driver/fmod/sound_driver_fmod.cpp b/nel/src/sound/driver/fmod/sound_driver_fmod.cpp index d98aa600f..2b250a1d3 100644 --- a/nel/src/sound/driver/fmod/sound_driver_fmod.cpp +++ b/nel/src/sound/driver/fmod/sound_driver_fmod.cpp @@ -496,36 +496,20 @@ bool getTag (std::string &result, const char *tag, FSOUND_STREAM *stream) } /** Get music info. Returns false if the song is not found or the function is not implemented. - * \param filepath path to file, CPath::lookup done by driver + * \param filepath full path to file * \param artist returns the song artist (empty if not available) * \param title returns the title (empty if not available) */ bool CSoundDriverFMod::getMusicInfo(const std::string &filepath, std::string &artist, std::string &title, float &length) { - /* Open a stream, get the tag if it exists, close the stream */ - string pathName = CPath::lookup(filepath, false); - uint32 fileOffset = 0, fileSize = 0; - if (pathName.empty()) + if (filepath.empty() || !CFile::fileExists(filepath)) { nlwarning("NLSOUND FMod Driver: Music file %s not found!", filepath.c_str()); return false; } - // if the file is in a bnp - if (pathName.find('@') != string::npos) - { - if (CBigFile::getInstance().getFileInfo(pathName, fileSize, fileOffset)) - { - // set pathname to bnp - pathName = pathName.substr(0, pathName.find('@')); - } - else - { - nlwarning("NLSOUND FMod Driver: BNP BROKEN"); - return false; - } - } - FSOUND_STREAM *stream = FSOUND_Stream_Open((const char *)CPath::lookup(filepath, false).c_str(), FSOUND_2D, (sint)fileOffset, (sint)fileSize); + uint32 fileOffset = 0, fileSize = 0; + FSOUND_STREAM *stream = FSOUND_Stream_Open(filepath.c_str(), FSOUND_2D, (sint)fileOffset, (sint)fileSize); if (stream) { getTag(artist, "ARTIST", stream); diff --git a/nel/src/sound/driver/fmod/sound_driver_fmod.h b/nel/src/sound/driver/fmod/sound_driver_fmod.h index db82cde6e..73d3b8673 100644 --- a/nel/src/sound/driver/fmod/sound_driver_fmod.h +++ b/nel/src/sound/driver/fmod/sound_driver_fmod.h @@ -112,7 +112,7 @@ public: virtual IMusicChannel *createMusicChannel(); /** Get music info. Returns false if the song is not found or the function is not implemented. - * \param filepath path to file, CPath::lookup done by driver + * \param filepath full path to file * \param artist returns the song artist (empty if not available) * \param title returns the title (empty if not available) */ diff --git a/nel/src/sound/driver/xaudio2/source_xaudio2.cpp b/nel/src/sound/driver/xaudio2/source_xaudio2.cpp index 785ce0565..273c6ee60 100644 --- a/nel/src/sound/driver/xaudio2/source_xaudio2.cpp +++ b/nel/src/sound/driver/xaudio2/source_xaudio2.cpp @@ -480,7 +480,7 @@ void CSourceXAudio2::setLooping(bool l) _SourceVoice->GetState(&voice_state); if (voice_state.BuffersQueued) { - nlwarning(NLSOUND_XAUDIO2_PREFIX "Not playing but buffer already queued while switching loop mode!?! Flush and requeue"); + // nlwarning(NLSOUND_XAUDIO2_PREFIX "Not playing but buffer already queued while switching loop mode!?! Flush and requeue"); if (FAILED(_SourceVoice->FlushSourceBuffers())) nlwarning(NLSOUND_XAUDIO2_PREFIX "FAILED FlushSourceBuffers"); // queue buffer with correct looping parameters diff --git a/nel/src/sound/music_channel_fader.cpp b/nel/src/sound/music_channel_fader.cpp index ea2cc6341..70ab890d2 100644 --- a/nel/src/sound/music_channel_fader.cpp +++ b/nel/src/sound/music_channel_fader.cpp @@ -147,7 +147,7 @@ void CMusicChannelFader::updateVolume() */ bool CMusicChannelFader::play(const std::string &filepath, uint xFadeTime, bool async, bool loop) { - stop(xFadeTime); + bool stopped = stop(xFadeTime); // Find the next best free music channel uint nextFader = _MaxMusicFader; @@ -164,7 +164,7 @@ bool CMusicChannelFader::play(const std::string &filepath, uint xFadeTime, bool // Play a song in it :) _CMusicFader &fader = _MusicFader[_ActiveMusicFader]; - if (xFadeTime) fader.fadeIn(xFadeTime); + if (xFadeTime && !stopped) fader.fadeIn(xFadeTime); // only fade in when fading out else fader.XFadeVolume = 1.0f; fader.Playing = true; updateVolume(); // make sure at ok volume to start :) @@ -173,12 +173,17 @@ bool CMusicChannelFader::play(const std::string &filepath, uint xFadeTime, bool } /// Stop the music previously loaded and played (the Memory is also freed) -void CMusicChannelFader::stop(uint xFadeTime) +bool CMusicChannelFader::stop(uint xFadeTime) { if (xFadeTime) { + bool stopped = true; for (uint i = 0; i < _MaxMusicFader; ++i) if (_MusicFader[i].Playing) + { _MusicFader[i].fadeOut(xFadeTime); + stopped = false; // fading + } + return stopped; } else { @@ -188,6 +193,7 @@ void CMusicChannelFader::stop(uint xFadeTime) _MusicFader[i].Fade = false; _MusicFader[i].Playing = false; } + return true; } } diff --git a/nel/src/sound/stream_file_source.cpp b/nel/src/sound/stream_file_source.cpp index fbd720a89..50d9bda97 100644 --- a/nel/src/sound/stream_file_source.cpp +++ b/nel/src/sound/stream_file_source.cpp @@ -108,6 +108,13 @@ void CStreamFileSource::play() //{ // nlwarning("Already waiting for play"); //} + std::string filepath = getStreamFileSound()->getFilePath(); + m_LookupPath = NLMISC::CPath::lookup(filepath, false, false); + if (m_LookupPath.empty()) + { + nlwarning("Music file %s does not exist!", filepath.c_str()); + return; + } if (!getStreamFileSound()->getAsync()) { if (!prepareDecoder()) @@ -272,7 +279,8 @@ bool CStreamFileSource::prepareDecoder() if (!m_AudioDecoder) { // load the file - m_AudioDecoder = IAudioDecoder::createAudioDecoder(getStreamFileSound()->getFilePath(), getStreamFileSound()->getAsync(), getStreamFileSound()->getLooping()); + nlassert(!m_LookupPath.empty()); + m_AudioDecoder = IAudioDecoder::createAudioDecoder(m_LookupPath, getStreamFileSound()->getAsync(), getStreamFileSound()->getLooping()); if (!m_AudioDecoder) { nlwarning("Failed to create IAudioDecoder, likely invalid format"); diff --git a/nel/src/web/http_client_curl.cpp b/nel/src/web/http_client_curl.cpp index 1ec244cd2..10bb0776c 100644 --- a/nel/src/web/http_client_curl.cpp +++ b/nel/src/web/http_client_curl.cpp @@ -191,7 +191,11 @@ bool CCurlHttpClient::receive(string &res, bool verbose) // *************************************************************************** void CCurlHttpClient::disconnect() { - curl_easy_cleanup(_Curl); + if (_CurlStruct) + { + curl_easy_cleanup(_Curl); + _CurlStruct = NULL; + } curl_global_cleanup(); } diff --git a/nel/tools/3d/build_clodtex/lod_texture_builder.cpp b/nel/tools/3d/build_clodtex/lod_texture_builder.cpp index d7ca00e9f..b0ff316df 100644 --- a/nel/tools/3d/build_clodtex/lod_texture_builder.cpp +++ b/nel/tools/3d/build_clodtex/lod_texture_builder.cpp @@ -135,6 +135,9 @@ bool CLodTextureBuilder::computeTexture(const CMeshMRM &meshMRM, NL3D::CLodCha const uint8 *srcPos= (const uint8*)vba.getVertexCoordPointer(); const uint8 *srcNormal= (const uint8*)vba.getNormalCoordPointer(); const uint8 *srcUV= (const uint8*)vba.getTexCoordPointer(); + nlassert(srcPos); + nlassert(srcNormal); + nlassert(srcUV); uint vertexSize = VB.getVertexSize(); // For the more precise lod uint lodId= meshMRM.getNbLod()-1; diff --git a/nel/tools/build_gamedata/c1_shard_patch.py b/nel/tools/build_gamedata/c1_shard_patch.py index b67b053a8..e67314cd8 100755 --- a/nel/tools/build_gamedata/c1_shard_patch.py +++ b/nel/tools/build_gamedata/c1_shard_patch.py @@ -49,6 +49,9 @@ printLog(log, "-------") printLog(log, time.strftime("%Y-%m-%d %H:%MGMT", time.gmtime(time.time()))) printLog(log, "") +# Find tools +SevenZip = findTool(log, ToolDirectories, SevenZipTool, ToolSuffix) + # List the directories that will be used archiveDirectories = [ ] for dir in InstallShardDataDirectories: @@ -89,23 +92,29 @@ else: printLog(log, "") if not args.admininstall: - printLog(log, ">>> Create new version <<<") - newVersion = 1 - vstr = str(newVersion).zfill(6) - vpath = PatchmanBridgeServerDirectory + "/" + vstr - while os.path.exists(vpath): - newVersion = newVersion + 1 + if SevenZip == "": + toolLogFail(log, SevenZipTool, ToolSuffix) + else: + printLog(log, ">>> Create new version <<<") + newVersion = 1 vstr = str(newVersion).zfill(6) vpath = PatchmanBridgeServerDirectory + "/" + vstr - mkPath(log, vpath) - for dir in archiveDirectories: - mkPath(log, ShardInstallDirectory + "/" + dir) - tgzPath = vpath + "/" + dir + ".tgz" - printLog(log, "WRITE " + tgzPath) - tar = tarfile.open(tgzPath, "w:gz") - tar.add(ShardInstallDirectory + "/" + dir, arcname = dir) - tar.close() - printLog(log, "") + while os.path.exists(vpath): + newVersion = newVersion + 1 + vstr = str(newVersion).zfill(6) + vpath = PatchmanBridgeServerDirectory + "/" + vstr + mkPath(log, vpath) + for dir in archiveDirectories: + mkPath(log, ShardInstallDirectory + "/" + dir) + # tgzPath = vpath + "/" + dir + ".tgz" + # printLog(log, "WRITE " + tgzPath) + # tar = tarfile.open(tgzPath, "w:gz") + # tar.add(ShardInstallDirectory + "/" + dir, arcname = dir) + # tar.close() + sevenZipPath = vpath + "/" + dir + ".7z" + printLog(log, "WRITE " + sevenZipPath) + subprocess.call([ SevenZip, "a", sevenZipPath, ShardInstallDirectory + "/" + dir ]) + printLog(log, "") log.close() if os.path.isfile("c1_shard_patch.log"): diff --git a/nel/tools/build_gamedata/configuration/tools.py b/nel/tools/build_gamedata/configuration/tools.py index ebb1d07da..ee933c8e9 100755 --- a/nel/tools/build_gamedata/configuration/tools.py +++ b/nel/tools/build_gamedata/configuration/tools.py @@ -98,3 +98,4 @@ PatchGenTool = "patch_gen" TranslationToolsTool = "translation_tools" BuildWorldPackedColTool = "build_world_packed_col" R2IslandsTexturesTool = "r2_islands_textures" +SevenZipTool = "7za" diff --git a/nel/tools/build_gamedata/d1_client_patch.py b/nel/tools/build_gamedata/d1_client_patch.py index ea4cc742c..5237542f6 100755 --- a/nel/tools/build_gamedata/d1_client_patch.py +++ b/nel/tools/build_gamedata/d1_client_patch.py @@ -123,7 +123,9 @@ else: printLog(log, "") printLog(log, ">>> Make bnp <<<") targetPath = ClientPatchDirectory + "/bnp" + tagPath = ClientPatchDirectory + "/bnp_tag" mkPath(log, targetPath) + mkPath(log, tagPath) for category in InstallClientData: packExt = ".bnp" if (category["StreamedPackages"]): @@ -133,25 +135,32 @@ else: sourcePath = InstallDirectory + "/" + package[0] mkPath(log, sourcePath) targetBnp = targetPath + "/" + package[0] + packExt + tagBnp = tagPath + "/" + package[0] + packExt + ".tag" if (len(package[1]) > 0): targetBnp = targetPath + "/" + package[1][0] + tagBnp = tagPath + "/" + package[1][0] + ".tag" printLog(log, "TARGET " + package[1][0]) needUpdateBnp = 1 if (len(package) > 2): - needUpdateBnp = needUpdate(log, sourcePath + "/" + package[2], targetBnp) + needUpdateBnp = needUpdate(log, sourcePath + "/" + package[2], tagBnp) else: - needUpdateBnp = needUpdateDirNoSubdirFile(log, sourcePath, targetBnp) + needUpdateBnp = needUpdateDirNoSubdirFile(log, sourcePath, tagBnp) if (needUpdateBnp): + subRet = 0 + open(tagBnp, 'a').close() + os.utime(tagBnp, None) if (category["StreamedPackages"]): printLog(log, "SNP " + targetBnp) # cwDir = os.getcwd().replace("\\", "/") # toolDir = os.path.dirname(Lzma).replace("\\", "/") # os.chdir(toolDir) - subprocess.call([ SnpMake, "-p", sourcePath, targetBnp, ClientPatchDirectory + "/stream" ] + package[1][1:]) + subRet = subprocess.call([ SnpMake, "-p", sourcePath, targetBnp, ClientPatchDirectory + "/stream" ] + package[1][1:]) # os.chdir(cwDir) else: printLog(log, "BNP " + targetBnp) - subprocess.call([ BnpMake, "-p", sourcePath, "-o", targetBnp ] + package[1][1:]) + subRet = subprocess.call([ BnpMake, "-p", sourcePath, "-o", targetBnp ] + package[1][1:]) + if (subRet != 0): + os.remove(tagBnp) else: printLog(log, "SKIP " + targetBnp) printLog(log, "") diff --git a/nel/tools/build_gamedata/processes/shape/2_build.py b/nel/tools/build_gamedata/processes/shape/2_build.py index f261473fe..86a3b6a99 100755 --- a/nel/tools/build_gamedata/processes/shape/2_build.py +++ b/nel/tools/build_gamedata/processes/shape/2_build.py @@ -74,6 +74,13 @@ else: printLog(log, ">>> Copy Shape <<<") copyFilesExtNoTreeIfNeeded(log, shapeDirectory, ExportBuildDirectory + "/" + ShapeClodtexBuildDirectory, ".shape") +printLog(log, ">>> Copy non-ShadowSkin non-CLodTex Shape <<<") +shapeDirectory = ExportBuildDirectory + "/" + ShapeNotOptimizedExportDirectory +mkPath(log, shapeDirectory) +mkPath(log, ExportBuildDirectory + "/" + ShapeClodtexBuildDirectory) +copyFilesExtNoTreeIfNeeded(log, shapeDirectory, ExportBuildDirectory + "/" + ShapeClodtexBuildDirectory, ".shape") +shapeDirectory = ExportBuildDirectory + "/" + ShapeClodtexBuildDirectory + # copy lightmap_not_optimized to lightmap printLog(log, ">>> Optimize lightmaps <<<") loPathLightmapsOriginal = ExportBuildDirectory + "/" + ShapeLightmapNotOptimizedExportDirectory diff --git a/ryzom/client/client_default.cfg b/ryzom/client/client_default.cfg index 7d134ad01..f18cd06a2 100644 --- a/ryzom/client/client_default.cfg +++ b/ryzom/client/client_default.cfg @@ -338,6 +338,9 @@ R2EDMaxMapScale = 8.0; WindowSnapInvert = 0; WindowSnapDistance = 10; +WindowSnapDistance_min = 0; +WindowSnapDistance_max = 50; +WindowSnapDistance_step = 1; ////////////////// // SOUND CONFIG // diff --git a/ryzom/client/src/character_cl.cpp b/ryzom/client/src/character_cl.cpp index 447ce8e3d..76263ee56 100644 --- a/ryzom/client/src/character_cl.cpp +++ b/ryzom/client/src/character_cl.cpp @@ -1120,7 +1120,7 @@ void CCharacterCL::computeAnimSet() // Use the generic method to compute the animation set. if(!::computeAnimSet(_CurrentAnimSet[MOVE], _Mode, _Sheet->getAnimSetBaseName(), _Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet, _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet, !modeWithHiddenItems())) { - //nlwarning("CH:computeAnimSet:%d: pb when trying to compute the animset. Sheet Id '%u(%s)'.", _Slot, _SheetId.asInt(), _SheetId.toString().c_str()); + nlwarning("CH:computeAnimSet:%d: pb when trying to compute the animset. Sheet Id '%u(%s)'.", _Slot, _SheetId.asInt(), _SheetId.toString().c_str()); } }// computeAnimSet // @@ -3360,7 +3360,7 @@ void CCharacterCL::showOrHideBodyParts( bool objectsVisible ) lHandInstIdx = SLOTTYPE::LEFT_HAND_SLOT; // hide gloves(armor) if player has magician amplifier - if( _Items[rHandInstIdx].Sheet && (_Items[rHandInstIdx].Sheet->ItemType == ITEM_TYPE::MAGICIAN_STAFF) ) + if( _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet && (_Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet->ItemType == ITEM_TYPE::MAGICIAN_STAFF) ) { if( !_Instances[SLOTTYPE::HANDS_SLOT].Current.empty() ) _Instances[SLOTTYPE::HANDS_SLOT].Current.hide(); @@ -3378,8 +3378,9 @@ void CCharacterCL::showOrHideBodyParts( bool objectsVisible ) if( !objectsVisible ) { // Right Hand + nlassert(SLOTTYPE::RIGHT_HAND_SLOT < _Items.size() && SLOTTYPE::LEFT_HAND_SLOT < _Items.size()); if(rHandInstIdx<_Instances.size()) - if( !(_Items[rHandInstIdx].Sheet && _Items[rHandInstIdx].Sheet->NeverHideWhenEquipped ) ) + if( !(_Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet && _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet->NeverHideWhenEquipped ) ) if(!_Instances[rHandInstIdx].Current.empty()) { _Instances[rHandInstIdx].Current.hide(); @@ -3387,7 +3388,7 @@ void CCharacterCL::showOrHideBodyParts( bool objectsVisible ) } // Left Hand if(lHandInstIdx <_Instances.size()) - if( !(_Items[lHandInstIdx].Sheet && _Items[lHandInstIdx].Sheet->NeverHideWhenEquipped ) ) + if( !(_Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet && _Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet->NeverHideWhenEquipped ) ) if(!_Instances[lHandInstIdx].Current.empty()) { _Instances[lHandInstIdx].Current.hide(); @@ -9293,14 +9294,14 @@ const char *CCharacterCL::getBoneNameFromBodyPart(BODY::TBodyPart part, BODY::TS const CItemSheet *CCharacterCL::getRightHandItemSheet() const { if (_RHandInstIdx == CEntityCL::BadIndex) return NULL; - return _Items[_RHandInstIdx].Sheet; + return _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet; } // ********************************************************************************************* const CItemSheet *CCharacterCL::getLeftHandItemSheet() const { if (_LHandInstIdx == CEntityCL::BadIndex) return NULL; - return _Items[_LHandInstIdx].Sheet; + return _Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet; } // *************************************************************************** diff --git a/ryzom/client/src/client_cfg.cpp b/ryzom/client/src/client_cfg.cpp index 2131ed691..5b7f4290e 100644 --- a/ryzom/client/src/client_cfg.cpp +++ b/ryzom/client/src/client_cfg.cpp @@ -465,7 +465,13 @@ CClientConfig::CClientConfig() SoundOn = true; // Default is with sound. DriverSound = SoundDrvAuto; SoundForceSoftwareBuffer = true; - SoundOutGameMusic = "main menu loop.ogg"; + StartMusic = "main theme air.ogg"; // Use at game startup (originally no music) + EmptySlotMusic = "loading music loop.ogg"; // Use in character selection for empty slots + LoadingMusic = "main menu loop.ogg"; // Main loading used after leaving character selection, and when going back to character selection + KamiTeleportMusic = "kami teleport.ogg"; // Kami teleport + KaravanTeleportMusic = "karavan teleport.ogg"; // Karavan teleport + TeleportLoadingMusic = "loading music loop.ogg"; // Use for generic teleportations + DeathMusic = "death.ogg"; // Player death SoundSFXVolume = 1.f; SoundGameMusicVolume = 1.f; SoundTPFade = 500; @@ -476,7 +482,7 @@ CClientConfig::CClientConfig() UserEntitySoundLevel = 0.5f; // Default volume for sound in 1st person UseEax = true; // Default to use EAX; UseADPCM = false; // Defualt to PCM sample, NO ADPCM - MaxTrack = 32; // DEfault to 32 track + MaxTrack = 32; // Default to 32 track ColorShout = CRGBA(150,0,0,255); // Default Shout color. ColorTalk = CRGBA(255,255,255,255); // Default Talk color. @@ -1248,7 +1254,13 @@ void CClientConfig::setValues() // SoundForceSoftwareBuffer READ_BOOL_FV(SoundForceSoftwareBuffer); // SoundOutGameMusic - READ_STRING_DEV(SoundOutGameMusic) + READ_STRING_DEV(StartMusic) + READ_STRING_DEV(EmptySlotMusic) + READ_STRING_DEV(LoadingMusic) + READ_STRING_DEV(KamiTeleportMusic) + READ_STRING_DEV(KaravanTeleportMusic) + READ_STRING_DEV(TeleportLoadingMusic) + READ_STRING_DEV(DeathMusic) // SoundSFXVolume READ_FLOAT_FV(SoundSFXVolume); // SoundGameMusicVolume diff --git a/ryzom/client/src/client_cfg.h b/ryzom/client/src/client_cfg.h index 437206661..9ef2bf3bc 100644 --- a/ryzom/client/src/client_cfg.h +++ b/ryzom/client/src/client_cfg.h @@ -348,8 +348,14 @@ struct CClientConfig /// SoundForceSoftwareBuffer bool SoundForceSoftwareBuffer; - /// The outgame music file - string SoundOutGameMusic; + /// Music files + string StartMusic; + string EmptySlotMusic; + string LoadingMusic; + string KamiTeleportMusic; + string KaravanTeleportMusic; + string TeleportLoadingMusic; + string DeathMusic; /// The Sound SFX Volume (0-1) (ie all but music) float SoundSFXVolume; diff --git a/ryzom/client/src/client_sheets/character_sheet.cpp b/ryzom/client/src/client_sheets/character_sheet.cpp index ab935268b..e6e5cbd00 100644 --- a/ryzom/client/src/client_sheets/character_sheet.cpp +++ b/ryzom/client/src/client_sheets/character_sheet.cpp @@ -213,6 +213,21 @@ void CCharacterSheet::build(const NLGEORGES::UFormElm &item) // IN LEFT HAND readEquipment(item, "Basics.Equipment.HandL", ObjectInLeftHand); + if (!ObjectInRightHand.IdItem) + { + std::string right; + item.getValueByName(right, "item_right"); + if (!right.empty()) + ObjectInRightHand.IdItem = ClientSheetsStrings.add(NLMISC::toLower(right)); + } + + if (!ObjectInLeftHand.IdItem) + { + std::string left; + item.getValueByName(left, "item_left"); + if (!left.empty()) + ObjectInLeftHand.IdItem = ClientSheetsStrings.add(NLMISC::toLower(left)); + } // Get the animation set Base Name. string AnimSetBaseName; diff --git a/ryzom/client/src/connection.cpp b/ryzom/client/src/connection.cpp index b53c571e6..47c45984d 100644 --- a/ryzom/client/src/connection.cpp +++ b/ryzom/client/src/connection.cpp @@ -273,6 +273,73 @@ void setOutGameFullScreen() CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768); } +// ------------------------------------------------------------------------------------------------ +class CSoundGlobalMenu +{ +public: + CSoundGlobalMenu() + { + _MusicWantedAsync= false; + _NbFrameBeforeChange= NbFrameBeforeChangeMax; + } + void reset(); + void setMusic(const string &music, bool async); + void updateSound(); +private: + string _MusicPlayed; + string _MusicWanted; + bool _MusicWantedAsync; + sint _NbFrameBeforeChange; + enum {NbFrameBeforeChangeMax= 10}; +}; + +void CSoundGlobalMenu::reset() +{ + _MusicPlayed.clear(); + _MusicWanted.clear(); +} + +void CSoundGlobalMenu::updateSound() +{ + // **** update the music played + // The first music played is the music played at loading, before select char + if (_MusicPlayed.empty()) + _MusicPlayed = toLower(LoadingMusic.empty() ? ClientCfg.StartMusic : LoadingMusic); + if (_MusicWanted.empty()) + _MusicWanted = toLower(LoadingMusic.empty() ? ClientCfg.StartMusic : LoadingMusic); + + // because music is changed when the player select other race for instance, + // wait the 3D to load (stall some secs) + + // if the wanted music is the same as the one currently playing, just continue playing + if(_MusicPlayed!=_MusicWanted) + { + // wait nbFrameBeforeChangeMax before actually changing the music + _NbFrameBeforeChange--; + if(_NbFrameBeforeChange<=0) + { + _MusicPlayed= _MusicWanted; + // play the music + if (SoundMngr != NULL) + SoundMngr->playMusic(_MusicPlayed, 500, _MusicWantedAsync, true, true); + } + } + + + // **** update mngr + if (SoundMngr != NULL) + SoundMngr->update(); +} + +void CSoundGlobalMenu::setMusic(const string &music, bool async) +{ + _MusicWanted= toLower(music); + _MusicWantedAsync= async; + // reset the counter + _NbFrameBeforeChange= NbFrameBeforeChangeMax; +} +static CSoundGlobalMenu SoundGlobalMenu; + // New version of the menu after the server connection // @@ -405,6 +472,8 @@ bool connection (const string &cookie, const string &fsaddr) InterfaceState = GLOBAL_MENU; } + // No loading music here, this is right before character selection, using the existing music + // Create the loading texture. We can't do that before because we need to add search path first. beginLoading (LoadBackground); UseEscapeDuringLoading = USE_ESCAPE_DURING_LOADING; @@ -507,6 +576,7 @@ bool reconnection() ProgressBar.setFontFactor(1.0f); // Init out game + SoundGlobalMenu.reset(); pIM->initOutGame(); // Hide cursor for interface @@ -522,6 +592,9 @@ bool reconnection() FarTP.setOutgame(); + if (SoundMngr) + SoundMngr->setupFadeSound(1.0f, 1.0f); + // these two globals sequence GlobalMenu to display the character select dialog WaitServerAnswer = true; userChar = true; @@ -556,6 +629,8 @@ bool reconnection() // this also kicks the state machine to sendReady() so we stop spinning in farTPmainLoop FarTP.setIngame(); + // Not loading music here, this is before character selection, keep existing music + // Create the loading texture. We can't do that before because we need to add search path first. beginLoading (LoadBackground); UseEscapeDuringLoading = USE_ESCAPE_DURING_LOADING; @@ -731,66 +806,6 @@ std::string buildPlayerNameForSaveFile(const ucstring &playerNameIn) return ret; } -// ------------------------------------------------------------------------------------------------ -class CSoundGlobalMenu -{ -public: - CSoundGlobalMenu() - { - _MusicWantedAsync= false; - _NbFrameBeforeChange= NbFrameBeforeChangeMax; - } - void setMusic(const string &music, bool async); - void updateSound(); -private: - string _MusicPlayed; - string _MusicWanted; - bool _MusicWantedAsync; - sint _NbFrameBeforeChange; - enum {NbFrameBeforeChangeMax= 10}; -}; - -void CSoundGlobalMenu::updateSound() -{ - // **** update the music played - // The first music played is the music played at loading, before select char - if(_MusicPlayed.empty()) - _MusicPlayed= toLower(ClientCfg.SoundOutGameMusic); - if(_MusicWanted.empty()) - _MusicWanted= toLower(ClientCfg.SoundOutGameMusic); - - // because music is changed when the player select other race for instance, - // wait the 3D to load (stall some secs) - - // if the wanted music is the same as the one currently playing, just continue playing - if(_MusicPlayed!=_MusicWanted) - { - // wait nbFrameBeforeChangeMax before actually changing the music - _NbFrameBeforeChange--; - if(_NbFrameBeforeChange<=0) - { - _MusicPlayed= _MusicWanted; - // play the music - if (SoundMngr != NULL) - SoundMngr->playMusic(_MusicPlayed, 500, _MusicWantedAsync, true, true); - } - } - - - // **** update mngr - if (SoundMngr != NULL) - SoundMngr->update(); -} - -void CSoundGlobalMenu::setMusic(const string &music, bool async) -{ - _MusicWanted= toLower(music); - _MusicWantedAsync= async; - // reset the counter - _NbFrameBeforeChange= NbFrameBeforeChangeMax; -} -static CSoundGlobalMenu SoundGlobalMenu; - static bool LuaBGDSuccessFlag = true; // tmp, for debug @@ -2041,8 +2056,8 @@ public: fromString(getParam(Params, "async"), async); // if empty name, return to default mode - if(sName.empty()) - sName= ClientCfg.SoundOutGameMusic; + if (sName.empty()) + sName = ClientCfg.EmptySlotMusic; // change the music SoundGlobalMenu.setMusic(sName, async); diff --git a/ryzom/client/src/decal.cpp b/ryzom/client/src/decal.cpp index e270a7c29..a16cb93bf 100644 --- a/ryzom/client/src/decal.cpp +++ b/ryzom/client/src/decal.cpp @@ -162,7 +162,9 @@ CDecal::CDecal() { DecalAttenuationVertexProgram = new CVertexProgramDecalAttenuation(); } - _ShadowMap = new CShadowMap(&(((CSceneUser *) Scene)->getScene().getRenderTrav().getShadowMapManager())); + + // initialized in render() as depends on scene + _ShadowMap = NULL; _Material.initUnlit(); _Diffuse = CRGBA::White; _Emissive = CRGBA::Black; @@ -251,7 +253,11 @@ CRGBA CDecal::getDiffuse() const // **************************************************************************** CDecal::~CDecal() { - delete _ShadowMap; + if (_ShadowMap) + { + delete _ShadowMap; + _ShadowMap = NULL; + } } // **************************************************************************** @@ -527,7 +533,12 @@ void CDecal::render(NL3D::UDriver &/* drv */, // float tileNear = Landscape->getTileNear(); // - nlassert(_ShadowMap); + if (!_ShadowMap) + { + _ShadowMap = new CShadowMap(&(((CSceneUser *) Scene)->getScene().getRenderTrav().getShadowMapManager())); + nlassert(_ShadowMap); + } + _ShadowMap->LocalClipPlanes.resize(4); CVector corners[4] = { diff --git a/ryzom/client/src/entity_cl.cpp b/ryzom/client/src/entity_cl.cpp index 14f3a1769..10d1573cf 100644 --- a/ryzom/client/src/entity_cl.cpp +++ b/ryzom/client/src/entity_cl.cpp @@ -378,6 +378,8 @@ void CEntityCL::SInstanceCL::updateCurrentFromLoading(NL3D::USkeleton Skeleton) sint stickID = Skeleton.getBoneIdByName(StickPoint); if(stickID != -1) Skeleton.stickObject(Current, stickID); + else + nlwarning("Skeleton '%s' is missing bone '%s' for object attachment.", Skeleton.getShapeName().c_str(), StickPoint.c_str()); } } diff --git a/ryzom/client/src/far_tp.cpp b/ryzom/client/src/far_tp.cpp index 0a594e540..80134f26b 100644 --- a/ryzom/client/src/far_tp.cpp +++ b/ryzom/client/src/far_tp.cpp @@ -1112,15 +1112,6 @@ void CFarTP::disconnectFromPreviousShard() beginLoading (StartBackground); UseEscapeDuringLoading = false; - // Play music and fade out the Game Sound - if (SoundMngr) - { - // Loading Music Loop.ogg - LoadingMusic = ClientCfg.SoundOutGameMusic; - SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true); - SoundMngr->fadeOutGameSound(ClientCfg.SoundTPFade); - } - // Change the tips selectTipsOfTheDay (rand()); @@ -1129,6 +1120,21 @@ void CFarTP::disconnectFromPreviousShard() ucstring nmsg("Loading..."); ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) ); ProgressBar.progress(0); + + // Play music and fade out the Game Sound + if (SoundMngr) + { + SoundMngr->fadeOutGameSound(ClientCfg.SoundTPFade); + + // Stop and enable music + SoundMngr->stopMusic(0); + SoundMngr->setupFadeSound(0.0f, 1.0f); + + // Loading Music Loop.ogg + LoadingMusic = ClientCfg.LoadingMusic; + // SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true); + SoundMngr->playMusic(LoadingMusic, 0, false, true, true); + } } // Disconnect from the FS diff --git a/ryzom/client/src/init.cpp b/ryzom/client/src/init.cpp index d6f6697bf..c0cfede93 100644 --- a/ryzom/client/src/init.cpp +++ b/ryzom/client/src/init.cpp @@ -1413,6 +1413,42 @@ void prelogInit() StereoDisplay->setDriver(Driver); // VR_DRIVER } + { + H_AUTO(InitRZSound) + + // Init the sound manager + nmsg = "Initializing sound manager..."; + ProgressBar.newMessage(ClientCfg.buildLoadingString(nmsg)); + if (ClientCfg.SoundOn) + { + nlassert(!SoundMngr); + SoundMngr = new CSoundManager(&ProgressBar); + try + { + SoundMngr->init(&ProgressBar); + } + catch(const Exception &e) + { + nlwarning("init : Error when creating 'SoundMngr' : %s", e.what()); + delete SoundMngr; + SoundMngr = NULL; + } + + // Play Music just after the SoundMngr is inited + if (SoundMngr) + { + // init the SoundMngr with backuped volume + SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume); + SoundMngr->setGameMusicVolume(ClientCfg.SoundGameMusicVolume); + + // Play the login screen music + SoundMngr->playMusic(ClientCfg.StartMusic, 0, true, true, true); + } + } + + CPath::memoryCompress(); // Because sound calls addSearchPath + } + nlinfo ("PROFILE: %d seconds for prelogInit", (uint32)(ryzomGetLocalTime ()-initStart)/1000); FPU_CHECKER_ONCE @@ -1555,55 +1591,6 @@ void postlogInit() // set the primitive context CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig; - { - H_AUTO(InitRZSound) - - // Init the sound manager - nmsg = "Initializing sound manager..."; - ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) ); - if(ClientCfg.SoundOn) - { - SoundMngr = new CSoundManager(&ProgressBar); - try - { - SoundMngr->init(&ProgressBar); - } - catch(const Exception &e) - { - nlwarning("init : Error when creating 'SoundMngr' : %s", e.what()); - delete SoundMngr; - SoundMngr = NULL; - } - - // Play Music just after the SoundMngr is inited - if(SoundMngr) - { - // init the SoundMngr with backuped volume - SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume); - SoundMngr->setGameMusicVolume(ClientCfg.SoundGameMusicVolume); - - // no fadein, and not async because don't work well because of loading in the main thread - // Force use GameMusic volume - const uint fadeInTime= 500; - SoundMngr->playMusic(ClientCfg.SoundOutGameMusic, fadeInTime, false, true, true); - // Because of blocking loading, force the fadeIn - TTime t0= ryzomGetLocalTime(); - TTime t1; - while((t1=ryzomGetLocalTime())updateAudioMixerOnly(); - } - } - } - - CPath::memoryCompress(); // Because sound call addSearchPath - - initLast = initCurrent; - initCurrent = ryzomGetLocalTime(); - //nlinfo ("PROFILE: %d seconds (%d total) for Initializing sound manager", (uint32)(initCurrent-initLast)/1000, (uint32)(initCurrent-initStart)/1000); - } - { H_AUTO(InitRZShIdI) diff --git a/ryzom/client/src/init_main_loop.cpp b/ryzom/client/src/init_main_loop.cpp index 2b391114c..deeda2149 100644 --- a/ryzom/client/src/init_main_loop.cpp +++ b/ryzom/client/src/init_main_loop.cpp @@ -473,6 +473,27 @@ void initMainLoop() FPU_CHECKER_ONCE + if (SoundMngr) + { + // Loading Music + LoadingMusic = ClientCfg.LoadingMusic; + + // SoundMngr->playEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade, true); + // no fadein, and not async because don't work well because of loading in the main thread + // Force use GameMusic volume + const uint fadeInTime = 500; + SoundMngr->playMusic(LoadingMusic, fadeInTime, false, true, true); + // Because of blocking loading, force the fadeIn + TTime t0 = ryzomGetLocalTime(); + TTime t1; + do + { + ProgressBar.progress(0); + SoundMngr->updateAudioMixerOnly(); + nlSleep(10); + } while ((t1 = ryzomGetLocalTime()) < t0 + fadeInTime); + } + // Get the interface manager CInterfaceManager *pIM = CInterfaceManager::getInstance(); diff --git a/ryzom/client/src/interface_v3/action_handler_game.cpp b/ryzom/client/src/interface_v3/action_handler_game.cpp index 58c00421b..5af8485d6 100644 --- a/ryzom/client/src/interface_v3/action_handler_game.cpp +++ b/ryzom/client/src/interface_v3/action_handler_game.cpp @@ -2822,24 +2822,6 @@ public: virtual void execute (CCtrlBase * /* pCaller */, const string &Params) { - /* // Previous version (multiple pressed on a desktop change a central window - uint desktop; - fromString(Params, desktop); - if (desktop getDbProp(dbNames[desktop], false); - if (pNL != NULL) - sValue = NLMISC::toString((sint32)pNL->getValue64()); - vector vecStr; - vecStr.push_back(procNames[desktop]); - vecStr.push_back(sValue); - CWidgetManager::getInstance()->runProcedure(procNames[desktop], NULL, vecStr); - }*/ - CInterfaceManager *pIM = CInterfaceManager::getInstance(); CGroupContainer *pGC = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:gestion_windows")); if (pGC == NULL) @@ -2850,11 +2832,14 @@ public: CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId("ui:interface:gestion_windows:close"); if (pIE != NULL) pIE->setActive(false); + bool switchDesktop = false; + CActionsManager *pAM = &Actions; if (!pAM->valide(CAction::CName("set_desktop",Params.c_str()))) { pGC->setActive(false); _FirstTime = true; + switchDesktop = true; } else // Key is down { @@ -2862,11 +2847,7 @@ public: if (_FirstTime) { _FirstTime = false; - - vector vecStr; - vecStr.push_back("tb_setdesktop"); - vecStr.push_back(Params); - CWidgetManager::getInstance()->runProcedure("tb_setdesktop", NULL, vecStr); + switchDesktop = true; } else // Not the first time { @@ -2876,6 +2857,13 @@ public: CWidgetManager::getInstance()->setTopWindow(pGC); } } + if (switchDesktop) + { + vector vecStr; + vecStr.push_back("tb_setdesktop"); + vecStr.push_back(Params); + CWidgetManager::getInstance()->runProcedure("tb_setdesktop", NULL, vecStr); + } } private: bool _FirstTime; diff --git a/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index 063ffdfad..e0e5f2e74 100644 --- a/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -540,6 +540,9 @@ CCtrlDraggable(param) _SapBuffIcon = "ico_sap.tga"; _StaBuffIcon = "ico_stamina.tga"; _FocusBuffIcon = "ico_focus.tga"; + + _RegenText = NULL; + _RegenTextValue = 0; } // ---------------------------------------------------------------------------- @@ -564,6 +567,11 @@ CDBCtrlSheet::~CDBCtrlSheet() Driver->deleteTextureFile(_GuildSymb); _GuildSymb = NULL; } + if (_RegenText) + { + delete _RegenText; + _RegenText = NULL; + } // ensure erase static if(this==_CurrMenuSheet) _CurrMenuSheet = NULL; @@ -2045,6 +2053,12 @@ void CDBCtrlSheet::draw() if (!_LastSheetId) { _RegenTickRange = CTickRange(); + if (_RegenText) + { + delete _RegenText; + _RegenText = NULL; + _RegenTextValue = 0; + } } else { @@ -2071,6 +2085,36 @@ void CDBCtrlSheet::draw() { rVR.drawQuad(_RenderLayer + 1, regenTris[tri], backTex, CRGBA::White, false); } + + if (!_RegenText) { + _RegenText = new CViewText(CViewBase::TCtorParam()); + _RegenText->setId(getId() + ":regen"); + _RegenText->setParent(_Parent); + _RegenText->setOverflowText(ucstring("")); + _RegenText->setModulateGlobalColor(false); + _RegenText->setMultiLine(false); + _RegenText->setTextMode(CViewText::ClipWord); + _RegenText->setFontSizing("0", "0"); + // TODO: font size / color hardcoded. + _RegenText->setFontSize(8); + _RegenText->setColor(CRGBA::White); + _RegenText->setShadow(true); + _RegenText->setActive(true); + _RegenText->updateTextContext(); + } + + // TODO: ticks in second hardcoded + uint32 nextValue = _RegenTickRange.EndTick > LastGameCycle ? (_RegenTickRange.EndTick - LastGameCycle) / 10 : 0; + if (_RegenTextValue != nextValue) + { + _RegenTextValue = nextValue; + _RegenText->setText(toString("%d", _RegenTextValue)); + _RegenText->updateTextContext(); + } + _RegenText->setXReal(_XReal+1); + _RegenText->setYReal(_YReal+2); + _RegenText->setRenderLayer(_RenderLayer+2); + _RegenText->draw(); } } diff --git a/ryzom/client/src/interface_v3/dbctrl_sheet.h b/ryzom/client/src/interface_v3/dbctrl_sheet.h index 8b89a91ed..e6ed7587b 100644 --- a/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -56,6 +56,7 @@ class COutpostBuildingSheet; namespace NLGUI { class CViewRenderer; + class CViewText; } class CDBCtrlSheet; @@ -736,6 +737,8 @@ protected: sint8 _ArmourColorIndex; CTickRange _RegenTickRange; + NLGUI::CViewText *_RegenText; + uint32 _RegenTextValue; /// D'n'd sint32 _DragX, _DragY; diff --git a/ryzom/client/src/interface_v3/group_map.cpp b/ryzom/client/src/interface_v3/group_map.cpp index 5245ca304..17e75486a 100644 --- a/ryzom/client/src/interface_v3/group_map.cpp +++ b/ryzom/client/src/interface_v3/group_map.cpp @@ -1333,15 +1333,18 @@ void CGroupMap::checkCoords() { if( _AnimalLM[i] ) { + // update pos + sint32 px, py; + _AnimalPosStates[i]->getPos(px, py); + updateLMPosFromDBPos(_AnimalLM[i], px, py); + if (_IsIsland) { _AnimalLM[i]->setActive(false); } - else + else if (_AnimalLM[i]->getActive()) { - _AnimalLM[i]->setActive(true); // update texture from animal status - CInterfaceManager *pIM= CInterfaceManager::getInstance(); CCDBNodeLeaf *statusNode = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d", i) + ":STATUS", false); if (statusNode && ANIMAL_STATUS::isInStable((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) ) { @@ -1372,11 +1375,6 @@ void CGroupMap::checkCoords() case ANIMAL_TYPE::Demon: sPrefix = "uiPATitleDemon"; break; } _AnimalLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(sPrefix+toString(i+1))); - - // update pos - sint32 px, py; - _AnimalPosStates[i]->getPos(px, py); - updateLMPosFromDBPos(_AnimalLM[i], px, py); } } } @@ -2473,7 +2471,8 @@ void CGroupMap::updateMatchedLandmarks() std::vector > params; params.clear(); params.push_back(std::pair("id", toString("lm%d", k))); - params.push_back(std::pair("tooltip", _MatchedLandmarks[k].Title.toUtf8())); + // ctrl base expects utf8 string to start with "u:" + params.push_back(std::pair("tooltip", "u:" + _MatchedLandmarks[k].Title.toUtf8())); params.push_back(std::pair("index", toString(k))); CInterfaceGroup *g = CWidgetManager::getInstance()->getParser()->createGroupInstance("lm_search_result", pL->getId(), params); @@ -2677,7 +2676,7 @@ void CGroupMap::setLandmarkFilter(const std::string &s) if (!s.empty()) { ucstring ucs; ucs.fromUtf8(s); - splitUCString(toLower(s), ucstring(" "), _LandmarkFilter); + splitUCString(toLower(ucs), ucstring(" "), _LandmarkFilter); } // recreate landmarks diff --git a/ryzom/client/src/interface_v3/input_handler_manager.cpp b/ryzom/client/src/interface_v3/input_handler_manager.cpp index 9d1e9292d..67a1b2350 100644 --- a/ryzom/client/src/interface_v3/input_handler_manager.cpp +++ b/ryzom/client/src/interface_v3/input_handler_manager.cpp @@ -271,16 +271,16 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) { - CViewPointer &rIP = *static_cast< CViewPointer* >( CWidgetManager::getInstance()->getPointer() ); + CViewPointer &rIP = *static_cast(CWidgetManager::getInstance()->getPointer()); NLGUI::CEventDescriptorMouse eventDesc; - sint32 x,y; - rIP.getPointerDispPos (x, y); - eventDesc.setX (x); - eventDesc.setY (y); + sint32 x, y; + rIP.getPointerDispPos(x, y); + eventDesc.setX(x); + eventDesc.setY(y); - bool handled= false; + bool handled = false; // button down ? static volatile bool doTest = false; @@ -291,7 +291,7 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) { if (_RecoverFocusLost) { - handled |= updateMousePos((CEventMouse&)event, eventDesc); // must update mouse pos here, + handled |= updateMousePos((CEventMouse&)event); // must update mouse pos here, // because when app window focus is gained by a mouse click, this is // the only place where we can retrieve mouse pos before a mouse move _RecoverFocusLost = false; @@ -299,10 +299,19 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) if (!handled) { if (R2::getEditor().isInitialized() - && (R2::isEditionCurrent() || R2::getEditor().getCurrentTool()) - ) + && (R2::isEditionCurrent() || R2::getEditor().getCurrentTool())) { - handled |= R2::getEditor().handleEvent(eventDesc); + const NLMISC::CEventMouseDown *mouseDownEvent = static_cast(&event); + if (mouseDownEvent->Button & NLMISC::leftButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouseleftdown); + handled |= R2::getEditor().handleEvent(eventDesc); + } + if (mouseDownEvent->Button & NLMISC::rightButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouserightdown); + handled |= R2::getEditor().handleEvent(eventDesc); + } } } handled |= inputHandler.handleMouseButtonDownEvent( event ); @@ -321,7 +330,7 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) // mouse move? else if(event == EventMouseMoveId) { - handled |= updateMousePos((CEventMouse&)event, eventDesc); + handled |= updateMousePos((CEventMouse&)event); } else if (event == EventMouseWheelId) { @@ -330,19 +339,77 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) } // if Event not handled, post to Action Manager - if( !handled ) + if (!handled) { - bool handled = false; if (R2::getEditor().isInitialized() - && (R2::isEditionCurrent() || R2::getEditor().getCurrentTool()) - ) + && (R2::isEditionCurrent() || R2::getEditor().getCurrentTool())) { - handled = R2::getEditor().handleEvent(eventDesc); + if (event == EventMouseDownId) + { + const NLMISC::CEventMouseDown *mouseDownEvent = static_cast(&event); + if (mouseDownEvent->Button & NLMISC::leftButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouseleftdown); + handled |= R2::getEditor().handleEvent(eventDesc); + } + if (mouseDownEvent->Button & NLMISC::rightButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouserightdown); + handled |= R2::getEditor().handleEvent(eventDesc); + } + } + else if (event == EventMouseUpId) + { + const NLMISC::CEventMouseUp *mouseUpEvent = static_cast(&event); + if (mouseUpEvent->Button & NLMISC::leftButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouseleftup); + handled |= R2::getEditor().handleEvent(eventDesc); + } + if (mouseUpEvent->Button & NLMISC::rightButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouserightup); + handled |= R2::getEditor().handleEvent(eventDesc); + } + } + else if (event == EventMouseDblClkId) + { + const NLMISC::CEventMouseDblClk *mouseDblClkEvent = static_cast(&event); + if (mouseDblClkEvent->Button & NLMISC::leftButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouseleftdblclk); + handled |= R2::getEditor().handleEvent(eventDesc); + } + if (mouseDblClkEvent->Button & NLMISC::rightButton) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mouserightdblclk); + handled |= R2::getEditor().handleEvent(eventDesc); + } + } + else + { + if (event == EventMouseWheelId) + { + const NLMISC::CEventMouseWheel *wheelEvent = static_cast(&event); + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mousewheel); + eventDesc.setWheel(wheelEvent->Direction ? 1 : -1); + handled = R2::getEditor().handleEvent(eventDesc); + } + else if (event == EventMouseMoveId) + { + eventDesc.setEventTypeExtended(CEventDescriptorMouse::mousemove); + handled = R2::getEditor().handleEvent(eventDesc); + } + else + { + nlwarning("R2 unknown mouse event '%s'", event.toString().c_str()); + } + } } if (!handled) { // post to Action Manager - FilteredEventServer.postEvent( event.clone() ); + FilteredEventServer.postEvent(event.clone()); } } } @@ -355,7 +422,7 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event) // *************************************************************************** -bool CInputHandlerManager::updateMousePos(NLMISC::CEventMouse &event, NLGUI::CEventDescriptorMouse &eventDesc) +bool CInputHandlerManager::updateMousePos(NLMISC::CEventMouse &event) { if (!IsMouseFreeLook()) return inputHandler.handleMouseMoveEvent( event ); diff --git a/ryzom/client/src/interface_v3/input_handler_manager.h b/ryzom/client/src/interface_v3/input_handler_manager.h index 7971ef9a8..4b078ee84 100644 --- a/ryzom/client/src/interface_v3/input_handler_manager.h +++ b/ryzom/client/src/interface_v3/input_handler_manager.h @@ -181,7 +181,7 @@ private: void parseKey(xmlNodePtr cur, std::vector &out); // return true if handled - bool updateMousePos(NLMISC::CEventMouse &event, NLGUI::CEventDescriptorMouse &eventDesc); + bool updateMousePos(NLMISC::CEventMouse &event); NLGUI::CInputHandler inputHandler; diff --git a/ryzom/client/src/interface_v3/interface_manager.cpp b/ryzom/client/src/interface_v3/interface_manager.cpp index 50acc2308..23440218e 100644 --- a/ryzom/client/src/interface_v3/interface_manager.cpp +++ b/ryzom/client/src/interface_v3/interface_manager.cpp @@ -1044,6 +1044,10 @@ void CInterfaceManager::initInGame() gc->setTarget(gc->getSavedTarget()); } + // rebuild mp3 player playlist if user reselected a char (songs are already scanned) + CAHManager::getInstance()->runActionHandler("music_player", NULL, "update_playlist"); + CAHManager::getInstance()->runActionHandler("music_player", NULL, "stop"); + CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHATLOG_STATE", false); if (node) { diff --git a/ryzom/client/src/interface_v3/inventory_manager.cpp b/ryzom/client/src/interface_v3/inventory_manager.cpp index 816f676e2..f84e38234 100644 --- a/ryzom/client/src/interface_v3/inventory_manager.cpp +++ b/ryzom/client/src/interface_v3/inventory_manager.cpp @@ -3648,15 +3648,23 @@ void CInventoryManager::onTradeChangeSession() // *************************************************************************** void CInventoryManager::updateItemInfoQueue() { + if (!ConnectionReadySent) // CONNECTION:READY not yet sent, so we cannot send requests yet! + { + // Caused by CNetworkConnection::reinit, and NLMISC::CCDBNodeBranch::resetData + // TODO: Item sheets are effectively being set to 0, any way to detect this in particular? + // Slots with sheet 0 won't have any info to request anyway! + // Remove this check in favour of the assert lower down when properly implemented. + nlwarning("Update item info queue (%i), but connection not ready", (int)_ItemInfoWaiters.size()); + return; + } + + // CONNECTION:READY not yet sent, so we cannot send requests yet! + nlassert(ConnectionReadySent || !_ItemInfoWaiters.size()); + // For All waiters, look if one need update. TItemInfoWaiters::iterator it; for(it= _ItemInfoWaiters.begin();it!=_ItemInfoWaiters.end();it++) { - /* \todo yoyo remove: temp patch to be sure that the client does not send messages before the - CONNECTION:READY is sent - */ - nlassert(ConnectionReadySent); - IItemInfoWaiter *waiter=*it; uint itemSlotId= waiter->ItemSlotId; TItemInfoMap::iterator it= _ItemInfoMap.find(itemSlotId); diff --git a/ryzom/client/src/interface_v3/music_player.cpp b/ryzom/client/src/interface_v3/music_player.cpp index 2deaa965b..56f97b554 100644 --- a/ryzom/client/src/interface_v3/music_player.cpp +++ b/ryzom/client/src/interface_v3/music_player.cpp @@ -28,6 +28,9 @@ #include "interface_manager.h" #include "../client_cfg.h" +#include "nel/misc/thread.h" +#include "nel/misc/mutex.h" + using namespace std; using namespace NLMISC; using namespace NL3D; @@ -48,6 +51,88 @@ extern UDriver *Driver; #define MP3_SAVE_REPEAT "UI:SAVE:MP3_REPEAT" CMusicPlayer MusicPlayer; +static NLMISC::CUnfairMutex MusicPlayerMutex; + +// *************************************************************************** +class CMusicPlayerWorker : public NLMISC::IRunnable +{ +private: + bool _Running; + IThread *_Thread; + + std::vector _Files; + +public: + CMusicPlayerWorker(): _Running(false), _Thread(NULL) + { + } + + ~CMusicPlayerWorker() + { + _Running = false; + if (_Thread) + { + _Thread->terminate(); + delete _Thread; + _Thread = NULL; + } + } + + bool isRunning() const { return _Running; } + + void run() + { + _Running = true; + + uint i = 0; + while(_Running && SoundMngr && i < _Files.size()) + { + // get copy incase _Files changes + std::string filename(_Files[i]); + + std::string title; + float length; + + if (SoundMngr->getMixer()->getSongTitle(filename, title, length)) + { + MusicPlayer.updateSong(filename, title, length); + } + + ++i; + } + + _Running = false; + _Files.clear(); + } + + // called from GUI + void getSongsInfo(const std::vector &filenames) + { + if (_Thread) + { + stopThread(); + } + + _Files = filenames; + + _Thread = IThread::create(this); + nlassert(_Thread != NULL); + _Thread->start(); + } + + void stopThread() + { + _Running = false; + if (_Thread) + { + _Thread->wait(); + delete _Thread; + _Thread = NULL; + } + } +}; + +static CMusicPlayerWorker MusicPlayerWorker; // *************************************************************************** @@ -69,11 +154,14 @@ bool CMusicPlayer::isShuffleEnabled() const return (NLGUI::CDBManager::getInstance()->getDbProp(MP3_SAVE_SHUFFLE)->getValue32() == 1); } - // *************************************************************************** -void CMusicPlayer::playSongs (const std::vector &songs) +void CMusicPlayer::playSongs (const std::vector &filenames) { - _Songs = songs; + _Songs.clear(); + for (uint i=0; i _Songs.size()) @@ -85,26 +173,113 @@ void CMusicPlayer::playSongs (const std::vector &songs) rebuildPlaylist(); // If pause, stop, else play will resume - if (_State == Paused) - _State = Stopped; + if (_State == Paused || _Songs.empty()) + stop(); + + // get song title/duration using worker thread + MusicPlayerWorker.getSongsInfo(filenames); } // *************************************************************************** -void CMusicPlayer::updatePlaylist(sint prevIndex) +void CMusicPlayer::updatePlaylist(uint index, bool state) { - CInterfaceElement *pIE; - std::string rowId; + if (index >= _Songs.size()) return; + + std::string rowId = toString("%s:s%d:bg", MP3_PLAYER_PLAYLIST_LIST, index); + CInterfaceElement *pIE = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(rowId)); + if (pIE) pIE->setActive(state); +} +void CMusicPlayer::updatePlaylist(sint prevIndex) +{ if (prevIndex >= 0 && prevIndex < _Songs.size()) { - rowId = toString("%s:s%d:bg", MP3_PLAYER_PLAYLIST_LIST, prevIndex); - pIE = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(rowId)); - if (pIE) pIE->setActive(false); + updatePlaylist(prevIndex, false); + } + + updatePlaylist(_CurrentSongIndex, true); +} + +// *************************************************************************** +// called from worker thread +void CMusicPlayer::updateSong(const std::string filename, const std::string title, float length) +{ + CAutoMutex mutex(MusicPlayerMutex); + + _SongUpdateQueue.push_back(CSongs(filename, title, length)); +} + +// *************************************************************************** +// called from GUI +void CMusicPlayer::updateSongs() +{ + CAutoMutex mutex(MusicPlayerMutex); + if (!_SongUpdateQueue.empty()) + { + for(uint i = 0; i < _SongUpdateQueue.size(); ++i) + { + updateSong(_SongUpdateQueue[i]); + } + _SongUpdateQueue.clear(); + } +} + +// *************************************************************************** +void CMusicPlayer::updateSong(const CSongs &song) +{ + uint index = 0; + while(index < _Songs.size()) + { + if (_Songs[index].Filename == song.Filename) + { + _Songs[index].Title = song.Title; + _Songs[index].Length = song.Length; + break; + } + + ++index; + } + if (index == _Songs.size()) + { + nlwarning("Unknown song file '%s'", song.Filename.c_str()); + return; + } + + std::string rowId(toString("%s:s%d", MP3_PLAYER_PLAYLIST_LIST, index)); + CInterfaceGroup *pIG = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(rowId)); + if (!pIG) + { + nlwarning("Playlist row '%s' not found", rowId.c_str()); + return; } - rowId = toString("%s:s%d:bg", MP3_PLAYER_PLAYLIST_LIST, _CurrentSongIndex); - pIE = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(rowId)); - if (pIE) pIE->setActive(true); + CViewText *pVT; + pVT = dynamic_cast(pIG->getView(TEMPLATE_PLAYLIST_SONG_TITLE)); + if (pVT) + { + pVT->setHardText(song.Title); + } + else + { + nlwarning("title element '%s' not found", TEMPLATE_PLAYLIST_SONG_TITLE); + } + + pVT = dynamic_cast(pIG->getView(TEMPLATE_PLAYLIST_SONG_DURATION)); + if (pVT) + { + uint min = (sint32)(song.Length / 60) % 60; + uint sec = (sint32)(song.Length) % 60; + uint hour = song.Length / 3600; + std::string duration(toString("%02d:%02d", min, sec)); + if (hour > 0) + duration = toString("%02d:", hour) + duration; + + pVT->setHardText(duration); + } + else + { + nlwarning("duration element '%s' not found", TEMPLATE_PLAYLIST_SONG_DURATION); + } } // *************************************************************************** @@ -131,12 +306,16 @@ void CMusicPlayer::rebuildPlaylist() _CurrentSongIndex = i; } - uint min = (sint32)(_Songs[i].Length / 60) % 60; - uint sec = (sint32)(_Songs[i].Length) % 60; - uint hour = _Songs[i].Length / 3600; - std::string duration(toString("%02d:%02d", min, sec)); - if (hour > 0) - duration = toString("%02d:", hour) + duration; + std::string duration("--:--"); + if (_Songs[i].Length > 0) + { + uint min = (sint32)(_Songs[i].Length / 60) % 60; + uint sec = (sint32)(_Songs[i].Length) % 60; + uint hour = _Songs[i].Length / 3600; + duration = toString("%02d:%02d", min, sec); + if (hour > 0) + duration = toString("%02d:", hour) + duration; + } vector< pair > vParams; vParams.push_back(pair("id", "s" + toString(i))); @@ -176,6 +355,17 @@ void CMusicPlayer::play (sint index) if(!SoundMngr) return; + if (_Songs.empty()) + { + index = 0; + createPlaylistFromMusic(); + } + + if (_Songs.empty()) + { + stop(); + return; + } sint prevSongIndex = _CurrentSongIndex; @@ -244,11 +434,15 @@ void CMusicPlayer::stop () return; // stop the music only if we are really playing (else risk to stop a background music!) - SoundMngr->stopMusic(0); + if (_State != Stopped) + SoundMngr->stopMusic(0); + _State = Stopped; _PlayStart = 0; _PauseTime = 0; + clearPlayingInfo(); + NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:MP3_PLAYING")->setValueBool(false); } @@ -284,15 +478,48 @@ void CMusicPlayer::next () } // *************************************************************************** +void CMusicPlayer::updatePlayingInfo(const std::string info) +{ + CViewText *pVT = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:mp3_player:screen:text")); + if (pVT) + { + pVT->setText(ucstring::makeFromUtf8(info)); + } +} +// *************************************************************************** +void CMusicPlayer::clearPlayingInfo() +{ + if (_Songs.empty()) + { + updatePlayingInfo(CI18N::get("uiNoFiles").toUtf8()); + } + else + { + updatePlayingInfo(""); + } +} + +// *************************************************************************** void CMusicPlayer::update () { if(!SoundMngr) + { + if (_State != Stopped) + { + _State = Stopped; + clearPlayingInfo(); + } return; + } + + if (MusicPlayerWorker.isRunning() || !_SongUpdateQueue.empty()) + { + updateSongs(); + } + if (_State == Playing) { - CViewText *pVT = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:mp3_player:screen:text")); - if (pVT) { TTime dur = (CTime::getLocalTime() - _PlayStart) / 1000; uint min = (dur / 60) % 60; @@ -302,7 +529,7 @@ void CMusicPlayer::update () std::string title(toString("%02d:%02d", min, sec)); if (hour > 0) title = toString("%02d:", hour) + title; title += " " + _CurrentSong.Title; - pVT->setText(ucstring::makeFromUtf8(title)); + updatePlayingInfo(title); } if (SoundMngr->isMusicEnded ()) @@ -323,15 +550,20 @@ void CMusicPlayer::update () } else { - SoundMngr->stopMusic(0); - _State = Stopped; + // remove active highlight from playlist + updatePlaylist(_CurrentSongIndex, false); + + stop(); + + // restart from top on next 'play' + _CurrentSongIndex = 0; } } } } // *************************************************************************** -static void addFromPlaylist(const std::string &playlist, std::vector &filenames) +static void addFromPlaylist(const std::string &playlist, const std::vector &extensions, std::vector &filenames) { static uint8 utf8Header[] = { 0xefu, 0xbbu, 0xbfu }; @@ -362,15 +594,82 @@ static void addFromPlaylist(const std::string &playlist, std::vector extensions; + SoundMngr->getMixer()->getMusicExtensions(extensions); + + // no format supported + if (extensions.empty()) + { + // in the very unlikely scenario + const ucstring message("Sound driver has no support for music."); + CInterfaceManager::getInstance()->displaySystemInfo(message, "SYS"); + nlinfo("%s", message.toUtf8().c_str()); + return; + } + std::string newPath = CPath::makePathAbsolute(CPath::standardizePath(ClientCfg.MediaPlayerDirectory), CPath::getCurrentPath(), true); + std::string extlist; + join(extensions, ", ", extlist); + extlist += ", m3u, m3u8"; + + std::string msg(CI18N::get("uiMk_system6").toUtf8()); + msg += ": " + newPath + " (" + extlist + ")"; + CInterfaceManager::getInstance()->displaySystemInfo(ucstring::makeFromUtf8(msg), "SYS"); + nlinfo("%s", msg.c_str()); + + // Recursive scan for files from media directory + vector filesToProcess; + CPath::getPathContent (newPath, true, false, true, filesToProcess); + + uint i; + std::vector filenames; + std::vector playlists; + + for (i = 0; i < filesToProcess.size(); ++i) + { + std::string ext = toLower(CFile::getExtension(filesToProcess[i])); + if (std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) + { + filenames.push_back(filesToProcess[i]); + } + else if (ext == "m3u" || ext == "m3u8") + { + playlists.push_back(filesToProcess[i]); + } + } + + // Add songs from playlists + for (i = 0; i < playlists.size(); ++i) + { + addFromPlaylist(playlists[i], extensions, filenames); + } + + // Sort songs by filename + sort(filenames.begin(), filenames.end()); + + playSongs(filenames); +} + // *************************************************************************** class CMusicPlayerPlaySongs: public IActionHandler { @@ -379,82 +678,16 @@ public: { if(!SoundMngr) { - CInterfaceManager::getInstance()->messageBox (CI18N::get ("uiSoundDisabled")); + // Do not show warning on volume change as its restored at startup + if (Params.find("volume") == std::string::npos) + CInterfaceManager::getInstance()->messageBox (CI18N::get ("uiMP3SoundDisabled")); + return; } if (Params == "play_songs") { - std::vector extensions; - SoundMngr->getMixer()->getMusicExtensions(extensions); - - // no format supported - if (extensions.empty()) - { - // in the very unlikely scenario - const ucstring message("Sound driver has no support for music."); - CInterfaceManager::getInstance()->displaySystemInfo(message, "SYS"); - nlinfo("%s", message.toUtf8().c_str()); - return; - } - std::string newPath = CPath::makePathAbsolute(CPath::standardizePath(ClientCfg.MediaPlayerDirectory), CPath::getCurrentPath(), true); - std::string extlist; - join(extensions, ", ", extlist); - extlist += ", m3u, m3u8"; - - std::string msg(CI18N::get("uiMk_system6").toUtf8()); - msg += ": " + newPath + " (" + extlist + ")"; - CInterfaceManager::getInstance()->displaySystemInfo(ucstring::makeFromUtf8(msg), "SYS"); - nlinfo("%s", msg.c_str()); - - // Recursive scan for files from media directory - vector filesToProcess; - CPath::getPathContent (newPath, true, false, true, filesToProcess); - - uint i; - std::vector filenames; - std::vector playlists; - - for (i = 0; i < filesToProcess.size(); ++i) - { - std::string ext = toLower(CFile::getExtension(filesToProcess[i])); - if (std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) - { - filenames.push_back(filesToProcess[i]); - } - else if (ext == "m3u" || ext == "m3u8") - { - playlists.push_back(filesToProcess[i]); - } - } - - // Sort songs by filename - sort (filenames.begin(), filenames.end()); - - // Add songs from playlists - for (i = 0; i < playlists.size(); ++i) - { - addFromPlaylist(playlists[i], filenames); - } - - // Build the songs array - std::vector songs; - for (i=0; igetMixer()->getSongTitle(filenames[i], song.Title, song.Length); - if (song.Length > 0) - songs.push_back (song); - } - - MusicPlayer.playSongs(songs); + MusicPlayer.createPlaylistFromMusic(); } else if (Params == "update_playlist") { diff --git a/ryzom/client/src/interface_v3/music_player.h b/ryzom/client/src/interface_v3/music_player.h index 549fa169d..febfde719 100644 --- a/ryzom/client/src/interface_v3/music_player.h +++ b/ryzom/client/src/interface_v3/music_player.h @@ -42,12 +42,16 @@ public: class CSongs { public: + CSongs(std::string file = std::string(), std::string title = std::string(), float length = 0.f) + : Filename(file), Title(title), Length(length) + { } + std::string Filename; std::string Title; float Length; }; - void playSongs (const std::vector &songs); + void playSongs (const std::vector &filenames); void play (sint index = -1); // Play the song at current position, if playing, restart. If paused, resume. void pause (); void stop (); @@ -58,6 +62,10 @@ public: void update (); + // update currently playing song info/duration on main gui + void updatePlayingInfo(const std::string info); + void clearPlayingInfo(); + bool isRepeatEnabled() const; bool isShuffleEnabled() const; @@ -67,6 +75,20 @@ public: void shuffleAndRebuildPlaylist(); // Update playlist active row void updatePlaylist(sint prevIndex = -1); + // set/remove playlist highlight + void updatePlaylist(uint index, bool state); + + // Update single song title/duration on _Songs and on playlist + void updateSong(const CSongs &song); + + // Update _Songs and playlist from _SongUpdateQueue + void updateSongs(); + + // update song from worker thread + void updateSong(const std::string filename, const std::string title, float length); + + // scan music folder and rebuild playlist + void createPlaylistFromMusic(); private: @@ -74,6 +96,8 @@ private: CSongs _CurrentSong; uint _CurrentSongIndex; // If (!_Songs.empty()) must always be <_Songs.size() std::vector _Songs; + // updated info from worker thread + std::vector _SongUpdateQueue; // State enum TState { Stopped, Playing, Paused } _State; diff --git a/ryzom/client/src/login.cpp b/ryzom/client/src/login.cpp index c9c1fdeaf..cb6117744 100644 --- a/ryzom/client/src/login.cpp +++ b/ryzom/client/src/login.cpp @@ -3279,6 +3279,7 @@ bool loginIntroSkip; void loginIntro() { // Display of nevrax logo is done at init time (see init.cpp) just before addSearchPath (second one) +#if 0 for (uint i = 0; i < 1; i++) // previously display nevrax then nvidia { if (i != 0) @@ -3316,6 +3317,7 @@ void loginIntro() NLGUI::CDBManager::getInstance()->flushObserverCalls(); } } +#endif beginLoading(StartBackground); ProgressBar.finish(); } diff --git a/ryzom/client/src/main_loop.cpp b/ryzom/client/src/main_loop.cpp index a3f6f3059..356b00452 100644 --- a/ryzom/client/src/main_loop.cpp +++ b/ryzom/client/src/main_loop.cpp @@ -556,11 +556,11 @@ void clearBuffers() } // Sky is used to clear the frame buffer now, but if in line or point polygon mode, we should draw it - if (Driver->getPolygonMode() != UDriver::Filled) + if (Driver->getPolygonMode() != UDriver::Filled || !Filter3D[FilterSky]) { if (!Driver->isLost()) { - Driver->clearBuffers (CRGBA(127, 127, 127)); + Driver->clearBuffers (ClientCfg.BGColor); } } } @@ -2240,19 +2240,21 @@ bool mainLoop() { StartPlayTime = NLMISC::CTime::getLocalTime(); } + // Start background sound play now ! (nb: restarted if load just ended, or if sound re-enabled) if (SoundMngr) { H_AUTO_USE ( RZ_Client_Main_Loop_Sound ) - SoundMngr->playBackgroundSound(); - } - // Fade in Game Sound now (before endLoading) - if(SoundMngr) - { // fade out loading music - if(LoadingMusic==SoundMngr->getEventMusicPlayed()) + if (SoundMngr->getEventMusicPlayed() == LoadingMusic) + { SoundMngr->stopEventMusic(LoadingMusic, CSoundManager::LoadingMusicXFade); + } + + SoundMngr->playBackgroundSound(); + + // Fade in Game Sound now (before endLoading) // fade in game sound SoundMngr->fadeInGameSound(ClientCfg.SoundTPFade); } @@ -2515,9 +2517,6 @@ bool mainLoop() Actions.enable(true); EditActions.enable(true); - // For stoping the outgame music, start after 30 frames, and duration of 3 seconds -// CMusicFader outgameFader(60, 3); - // check for banned player if (testPermanentBanMarkers()) { @@ -2527,6 +2526,9 @@ bool mainLoop() } } + // For stoping the outgame music, start after 30 frames, and duration of 3 seconds + outgameFader = CMusicFader(60, 3); + // Short reinit of the main loop after farTP or character reselection Ping.init(); updateLightDesc(); diff --git a/ryzom/client/src/main_loop_utilities.cpp b/ryzom/client/src/main_loop_utilities.cpp index 4243e15b0..4a4b2bc38 100644 --- a/ryzom/client/src/main_loop_utilities.cpp +++ b/ryzom/client/src/main_loop_utilities.cpp @@ -110,6 +110,9 @@ void updateFromClientCfg() if (ClientCfg.BilinearUI != LastClientCfg.BilinearUI) CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI); + CWidgetManager::getInstance()->setWindowSnapInvert(ClientCfg.WindowSnapInvert); + CWidgetManager::getInstance()->setWindowSnapDistance(ClientCfg.WindowSnapDistance); + //--------------------------------------------------- if (ClientCfg.WaitVBL != LastClientCfg.WaitVBL) { diff --git a/ryzom/client/src/net_manager.cpp b/ryzom/client/src/net_manager.cpp index 7ce27c4d5..642935869 100644 --- a/ryzom/client/src/net_manager.cpp +++ b/ryzom/client/src/net_manager.cpp @@ -1483,32 +1483,33 @@ void impulseTPCommon(NLMISC::CBitMemStream &impulse, bool hasSeason) void impulseTPCommon2(NLMISC::CBitMemStream &impulse, bool hasSeason) { // choose a default screen if not setuped - if( LoadingBackground!=ResurectKamiBackground && LoadingBackground!=ResurectKaravanBackground && - LoadingBackground!=TeleportKamiBackground && LoadingBackground!=TeleportKaravanBackground) - LoadingBackground= TeleportKaravanBackground; + if (LoadingBackground != ResurectKamiBackground && LoadingBackground != ResurectKaravanBackground + && LoadingBackground != TeleportKamiBackground && LoadingBackground != TeleportKaravanBackground) + LoadingBackground = ElevatorBackground; // if resurect but user not dead, choose default. NB: this is a bug, the tp impulse should tell // which background to choose. \todo yoyo: this is a temp fix - if( UserEntity && !UserEntity->isDead() && - (LoadingBackground==ResurectKamiBackground || LoadingBackground==ResurectKaravanBackground) ) - LoadingBackground= TeleportKaravanBackground; + if (UserEntity && !UserEntity->isDead() && (LoadingBackground == ResurectKamiBackground || LoadingBackground == ResurectKaravanBackground)) + LoadingBackground = ElevatorBackground; // Play music according to the background - if(SoundMngr) + if (SoundMngr) { LoadingMusic.clear(); - if(LoadingBackground==TeleportKamiBackground) - LoadingMusic= "Kami Teleport.ogg"; - else if(LoadingBackground==TeleportKaravanBackground) - LoadingMusic= "Karavan Teleport.ogg"; - // if resurection, continue to play death music - else if(LoadingBackground==ResurectKamiBackground || LoadingBackground==ResurectKaravanBackground) - { - // noop - } - // default: loading music - else + switch (LoadingBackground) { - LoadingMusic= "Loading Music Loop.ogg"; + case TeleportKamiBackground: + LoadingMusic = ClientCfg.KamiTeleportMusic; + break; + case TeleportKaravanBackground: + LoadingMusic = ClientCfg.KaravanTeleportMusic; + break; + case ResurectKamiBackground: + case ResurectKaravanBackground: + // TODO: Resurrect music + break; + default: + LoadingMusic = ClientCfg.TeleportLoadingMusic; + break; } // start to play diff --git a/ryzom/client/src/r2/editor.cpp b/ryzom/client/src/r2/editor.cpp index 457cee562..8e146e9ad 100644 --- a/ryzom/client/src/r2/editor.cpp +++ b/ryzom/client/src/r2/editor.cpp @@ -5785,7 +5785,7 @@ void CEditor::scenarioUpdated(CObject* highLevel, bool willTP, uint32 initialAct } // projectInLua(_Scenario); // push on the lua stack - getLua().push(float(initialActIndex)); // example reconnect after test in act4 + getLua().push(initialActIndex); // example reconnect after test in act4 // update value in the framework callEnvFunc("onScenarioUpdated", 2); //nlwarning("Instance list now is :"); diff --git a/ryzom/client/src/release.cpp b/ryzom/client/src/release.cpp index 0477acce9..889bcee11 100644 --- a/ryzom/client/src/release.cpp +++ b/ryzom/client/src/release.cpp @@ -240,8 +240,8 @@ void releaseMainLoopReselect() // alredy called from farTPMainLoop() // --R2::getEditor().autoConfigRelease(IsInRingSession); - // Pause any user played music - MusicPlayer.pause(); + // stop any user played music + MusicPlayer.stop(); // only really needed at exit // --STRING_MANAGER::CStringManagerClient::instance()->flushStringCache(); @@ -390,8 +390,8 @@ void releaseMainLoop(bool closeConnection) // Release R2 editor if applicable R2::getEditor().autoConfigRelease(IsInRingSession); - // Pause any user played music - MusicPlayer.pause(); + // stop any user played music + MusicPlayer.stop(); // flush the server string cache STRING_MANAGER::CStringManagerClient::instance()->flushStringCache(); diff --git a/ryzom/client/src/user_entity.cpp b/ryzom/client/src/user_entity.cpp index 18cd832be..5c14bf82e 100644 --- a/ryzom/client/src/user_entity.cpp +++ b/ryzom/client/src/user_entity.cpp @@ -4309,20 +4309,19 @@ void CUserEntity::updatePreCollision(const NLMISC::TTime &time, CEntityCL *targe // test each frame if the mode has changed if(SoundMngr) { - string deadMusic= "death.ogg"; // Play/stop music if comes from or goes to dead - bool isDead= _Mode==MBEHAV::DEATH || _Mode==MBEHAV::SWIM_DEATH; + bool isDead = _Mode == MBEHAV::DEATH || _Mode == MBEHAV::SWIM_DEATH; // must start music? - if( isDead && SoundMngr->getEventMusicPlayed()!=deadMusic ) + if (isDead && SoundMngr->getEventMusicPlayed() != ClientCfg.DeathMusic) { - SoundMngr->playEventMusic(deadMusic, 0, true); + SoundMngr->playEventMusic(ClientCfg.DeathMusic, 0, true); } // must end music? - if( !isDead && SoundMngr->getEventMusicPlayed()==deadMusic ) + if (!isDead && SoundMngr->getEventMusicPlayed() == ClientCfg.DeathMusic) { - SoundMngr->stopEventMusic(deadMusic, CSoundManager::LoadingMusicXFade); + SoundMngr->stopEventMusic(ClientCfg.DeathMusic, CSoundManager::LoadingMusicXFade); } } } diff --git a/ryzom/tools/leveldesign/georges_dll/file_tree_view.cpp b/ryzom/tools/leveldesign/georges_dll/file_tree_view.cpp index 673c12d9a..e1a52d887 100644 --- a/ryzom/tools/leveldesign/georges_dll/file_tree_view.cpp +++ b/ryzom/tools/leveldesign/georges_dll/file_tree_view.cpp @@ -187,7 +187,7 @@ BOOL CFileTreeCtrl::OnNotify ( WPARAM wParam, LPARAM lParam, LRESULT* pResult ) { LPNMHDR pnmh = (LPNMHDR) lParam; // Tree ? - if (wParam == 0) + // if (wParam == 0) { switch (pnmh->code) { diff --git a/ryzom/tools/leveldesign/georges_dll/form_dialog.cpp b/ryzom/tools/leveldesign/georges_dll/form_dialog.cpp index a4d35fdcc..b4def1a14 100644 --- a/ryzom/tools/leveldesign/georges_dll/form_dialog.cpp +++ b/ryzom/tools/leveldesign/georges_dll/form_dialog.cpp @@ -720,6 +720,8 @@ void CFormDialog::onLastFocus () int CFormDialog::getWidget (uint dialogId) const { + if (dialogId == 0xFFFE) + dialogId = 0; for (uint i=0; iisDialog (dialogId)) @@ -1198,6 +1200,11 @@ void CFormDialog::onGetSubFocus (uint id) { // Get the widget int widget = getWidget (id); + if (widget < 0) + { + nldebug("Invalid widget id %d", (int)id); + return; + } WidgetFocused = widget; // Window view @@ -1584,7 +1591,7 @@ void CFormMemCombo::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, { // Create the mem combobox parent->setComboSpinSize (currentPos); - Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index, reg, theApp.RememberListSize); + Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE, reg, theApp.RememberListSize); parent->initWidget (Combo); // Create the spin @@ -1599,7 +1606,7 @@ void CFormMemCombo::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, { // Create the mem combobox parent->setComboBrowseSize (currentPos); - Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index, reg, theApp.RememberListSize); + Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE, reg, theApp.RememberListSize); parent->initWidget (Combo); // Create the spin @@ -1621,7 +1628,7 @@ void CFormMemCombo::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, { // Create the mem combobox parent->setComboSize (currentPos, parent->SmallWidget); - Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index, reg, theApp.RememberListSize); + Combo.create (WS_CHILD|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE, reg, theApp.RememberListSize); parent->initWidget (Combo); parent->getNextPos (currentPos); } @@ -1914,7 +1921,7 @@ void CFormCombo::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, ui parent->setComboSize (currentPos, parent->SmallWidget); RECT comboPos = currentPos; parent->adjusteComboSize (comboPos); - Combo.Create (WS_CHILD|WS_VSCROLL|WS_VISIBLE|CBS_DROPDOWNLIST|CBS_HASSTRINGS|WS_CHILD|WS_TABSTOP, comboPos, parent, dialog_index); + Combo.Create (WS_CHILD|WS_VSCROLL|WS_VISIBLE|CBS_DROPDOWNLIST|CBS_HASSTRINGS|WS_CHILD|WS_TABSTOP, comboPos, parent, dialog_index ? dialog_index : 0xFFFE); parent->initWidget (Combo); parent->getNextPos (currentPos); @@ -2097,7 +2104,7 @@ void CFormBigEdit::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, // Create the mem combobox parent->setBigEditSize (currentPos, parent->SmallWidget); - Edit.CreateEx (WS_EX_CLIENTEDGE, _T("EDIT"), _T(""), WS_VSCROLL|ES_OEMCONVERT|ES_MULTILINE|ES_WANTRETURN|WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL|ES_AUTOVSCROLL, currentPos, parent, dialog_index); + Edit.CreateEx (WS_EX_CLIENTEDGE, _T("EDIT"), _T(""), WS_VSCROLL|ES_OEMCONVERT|ES_MULTILINE|ES_WANTRETURN|WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL|ES_AUTOVSCROLL, currentPos, parent, dialog_index ? dialog_index : 0xFFFE); parent->initWidget (Edit); parent->getNextPos (currentPos); @@ -2271,7 +2278,7 @@ void CColorEdit::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, ui // Create the mem combobox parent->setColorSize (currentPos, parent->SmallWidget); - Color.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index); + Color.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE); parent->initWidget (Color); // Create the reset button @@ -2501,7 +2508,7 @@ void CListWidget::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, u // Create the mem combobox parent->setListSize (currentPos, parent->SmallWidget); - ListCtrl.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index); + ListCtrl.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE); parent->initWidget (ListCtrl); parent->getNextPos (currentPos); @@ -2759,7 +2766,7 @@ void CIconWidget::create (DWORD wStyle, RECT ¤tPos, CFormDialog *parent, u // Create the mem combobox parent->setEditSize (currentPos, parent->IconHeight, parent->IconHeight); - Icon.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index); + Icon.create (WS_CHILD|WS_VISIBLE|WS_TABSTOP, currentPos, parent, dialog_index ? dialog_index : 0xFFFE); parent->initWidget (Icon); parent->getNextPos (currentPos);