From 616faf1c516844c1988058694c79a108f6703078 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Thu, 12 Apr 2012 21:38:28 +0200 Subject: [PATCH 01/66] Fixed: #1298 Replace assert with warning when physical sound source fails to play --- code/nel/src/sound/simple_source.cpp | 8 ++++++++ code/nel/src/sound/stream_source.cpp | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/code/nel/src/sound/simple_source.cpp b/code/nel/src/sound/simple_source.cpp index 7c76533e3..cce62cffd 100644 --- a/code/nel/src/sound/simple_source.cpp +++ b/code/nel/src/sound/simple_source.cpp @@ -134,6 +134,7 @@ void CSimpleSource::play() || (_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > _SimpleSound->getMaxDistance() * _SimpleSound->getMaxDistance()) { // The sample buffer is not available, don't play (we don't know the length) + _WaitingForPlay = false; if (_Spawn) { if (_SpawnEndCb != 0) @@ -175,7 +176,14 @@ void CSimpleSource::play() // and play the sound bool play = pSource->play(); + +#ifdef NL_DEBUG nlassert(play); +#else + if (!play) + nlwarning("Failed to play physical sound source. This is a serious error"); +#endif + // nldebug("CSimpleSource %p : REAL play done", (CAudioMixerUser::IMixerEvent*)this); } else diff --git a/code/nel/src/sound/stream_source.cpp b/code/nel/src/sound/stream_source.cpp index 1397e87ac..221b0529e 100644 --- a/code/nel/src/sound/stream_source.cpp +++ b/code/nel/src/sound/stream_source.cpp @@ -156,6 +156,7 @@ void CStreamSource::play() if ((_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance()) { // Source is too far to play + m_WaitingForPlay = false; if (_Spawn) { if (_SpawnEndCb != NULL) @@ -165,7 +166,6 @@ void CStreamSource::play() #ifdef NLSOUND_DEBUG_STREAM nldebug("CStreamSource %p : play FAILED, source is too far away !", (CAudioMixerUser::IMixerEvent*)this); #endif - // m_WaitingForPlay = false; // not necessary, delete ensures waiting for thread stop return; } @@ -221,13 +221,13 @@ void CStreamSource::play() else { // No source available, kill. + m_WaitingForPlay = false; if (_Spawn) { if (_SpawnEndCb != NULL) _SpawnEndCb(this, _CbUserParam); delete this; } - m_WaitingForPlay = false; return; } } @@ -269,6 +269,9 @@ void CStreamSource::play() #ifdef NL_DEBUG nlassert(play); +#else + if (!play) + nlwarning("Failed to play physical sound source. This is a serious error"); #endif } From 444becf71d3ad2ee68fa7acb41024f019f976c52 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 03:06:52 +0200 Subject: [PATCH 02/66] Changed: #1461 Bad minimum value for comparing fast swim speed causes random switching between fast and slow swim speed particle effects --- code/ryzom/client/src/ground_fx_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/ryzom/client/src/ground_fx_manager.cpp b/code/ryzom/client/src/ground_fx_manager.cpp index 92267dd2a..2d3ce3810 100644 --- a/code/ryzom/client/src/ground_fx_manager.cpp +++ b/code/ryzom/client/src/ground_fx_manager.cpp @@ -64,7 +64,7 @@ CGroundFXManager::CGroundFXManager() : _MinSpeed(1.5f), _MaxSpeed(6.f), _SpeedWaterWalkFast(3.f), - _SpeedWaterSwimFast(3.f), + _SpeedWaterSwimFast(2.f), _MaxDist(50.f), _MaxNumFX(10), _NumFX(0), @@ -495,7 +495,7 @@ void CGroundFXManager::update(const NLMISC::CVectorD &camPos) break; case CInstance::Swim: if (speed == 0.f) fxName = "StepSwimIdle.ps"; - else if (speed > _SpeedWaterWalkFast) + else if (speed > _SpeedWaterSwimFast) { fxName = "StepSwimSpeed.ps"; fxNameUnderWater = "StepSwimSpeedUnderWater.ps"; From beae63c1a038f7c79d17ae36e86aa74446a2d930 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 03:10:13 +0200 Subject: [PATCH 03/66] Changed: Provide a fake sound name for fake CSound created by music channel --- code/nel/src/sound/source_music_channel.cpp | 15 ++++++++++++++- code/nel/src/sound/stream_file_sound.cpp | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/code/nel/src/sound/source_music_channel.cpp b/code/nel/src/sound/source_music_channel.cpp index bd8f152e0..677370dd3 100644 --- a/code/nel/src/sound/source_music_channel.cpp +++ b/code/nel/src/sound/source_music_channel.cpp @@ -54,6 +54,8 @@ CSourceMusicChannel::~CSourceMusicChannel() bool CSourceMusicChannel::play(const std::string &filepath, bool async, bool loop) { + // delete previous source if any + // note that this waits for the source's thread to finish if the source was still playing if (m_Source) delete m_Source; @@ -71,12 +73,14 @@ bool CSourceMusicChannel::play(const std::string &filepath, bool async, bool loo void CSourceMusicChannel::stop() { + // stop but don't delete the source, deleting source may cause waiting for thread if (m_Source) m_Source->stop(); } void CSourceMusicChannel::reset() { + // forces the source to be deleted, happens when audio mixer is reset delete m_Source; m_Source = NULL; } @@ -96,7 +100,16 @@ void CSourceMusicChannel::resume() bool CSourceMusicChannel::isEnded() { if (m_Source) - return m_Source->isEnded(); + { + if (m_Source->isEnded()) + { + // we can delete the source now without worrying about thread wait + delete m_Source; + m_Source = NULL; + return true; + } + return false; + } return true; } diff --git a/code/nel/src/sound/stream_file_sound.cpp b/code/nel/src/sound/stream_file_sound.cpp index 4fc17b51c..44da5a31d 100644 --- a/code/nel/src/sound/stream_file_sound.cpp +++ b/code/nel/src/sound/stream_file_sound.cpp @@ -73,6 +73,11 @@ void CStreamFileSound::serial(NLMISC::IStream &s) void CStreamFileSound::setMusicFilePath(const std::string &filePath, bool async, bool loop) { +#if !FINAL_VERSION + _Name = NLMISC::CStringMapper::map(std::string(""); +#else + _Name = NLMISC::CStringMapper::map(""); +#endif _ConeInnerAngle = NLMISC::Pi * 2; _ConeOuterAngle = NLMISC::Pi * 2; _Looping = loop; From abbded6e92e4eb94e1dee0ee2027b9befd85a96d Mon Sep 17 00:00:00 2001 From: kervala Date: Fri, 13 Apr 2012 09:36:51 +0200 Subject: [PATCH 04/66] Changed: #825 Remove all warnings when compiling Ryzom --- code/ryzom/client/src/interface_v3/interface_element.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/interface_element.h b/code/ryzom/client/src/interface_v3/interface_element.h index 24982cad2..0202618ba 100644 --- a/code/ryzom/client/src/interface_v3/interface_element.h +++ b/code/ryzom/client/src/interface_v3/interface_element.h @@ -361,7 +361,7 @@ public: */ virtual void forceOpen() { setActive(true); } - virtual void enableBlink(int /* numBlinks */ = 0) {} + virtual void enableBlink(uint /* numBlinks */ = 0) {} virtual void disableBlink() {} virtual bool getBlink() const { return false; } From 291a9562162ecaececa0be12e57dce3e86e9a481 Mon Sep 17 00:00:00 2001 From: kervala Date: Fri, 13 Apr 2012 10:07:06 +0200 Subject: [PATCH 05/66] Changed: #825 Remove all warnings when compiling Ryzom --- code/nel/include/nel/misc/bit_mem_stream.h | 6 ++-- code/nel/include/nel/misc/mem_stream.h | 4 +-- code/nel/src/misc/bit_mem_stream.cpp | 2 +- code/nel/src/misc/bitmap_jpeg.cpp | 2 +- code/nel/src/misc/co_task.cpp | 3 ++ code/nel/src/misc/command.cpp | 3 ++ code/nel/src/misc/common.cpp | 38 +++++++++++++++++++++- 7 files changed, 50 insertions(+), 8 deletions(-) diff --git a/code/nel/include/nel/misc/bit_mem_stream.h b/code/nel/include/nel/misc/bit_mem_stream.h index 3bddc20f7..b294d5454 100644 --- a/code/nel/include/nel/misc/bit_mem_stream.h +++ b/code/nel/include/nel/misc/bit_mem_stream.h @@ -394,7 +394,7 @@ public: * If you are using the stream only in output mode, you can use this method as a faster version * of clear() *if you don't serialize pointers*. */ - void resetBufPos() + virtual void resetBufPos() { // This is ensured in CMemStream::CMemStream() and CMemStream::clear() //if ( (!isReading()) && _Buffer.empty() ) @@ -477,7 +477,7 @@ public: } /// See doc in CMemStream::bufferToFill() - uint8 *bufferToFill( uint32 msgsize ) + virtual uint8 *bufferToFill( uint32 msgsize ) { _FreeBits = 8; _DbgInfo.clear(); @@ -654,7 +654,7 @@ public: virtual void serial(ucstring &b); virtual void serial(CBitMemStream &b) { serialMemStream(b); } - virtual void serialMemStream(CBitMemStream &b); + virtual void serialMemStream(CMemStream &b); //@} diff --git a/code/nel/include/nel/misc/mem_stream.h b/code/nel/include/nel/misc/mem_stream.h index 2102129dd..1da99a48d 100644 --- a/code/nel/include/nel/misc/mem_stream.h +++ b/code/nel/include/nel/misc/mem_stream.h @@ -301,7 +301,7 @@ public: * If you are using the stream only in output mode, you can use this method as a faster version * of clear() *if you don't serialize pointers*. */ - void resetBufPos() { _Buffer.Pos = 0; } + virtual void resetBufPos() { _Buffer.Pos = 0; } /** * Resize the message buffer and fill data at position 0. @@ -340,7 +340,7 @@ public: * fill it with raw data using any filling function (warning: don't fill more than 'msgsize' * bytes!), then you are ready to read, using serial(), the data you've just filled. */ - uint8 *bufferToFill( uint32 msgsize ) + virtual uint8 *bufferToFill( uint32 msgsize ) { #ifdef NL_DEBUG nlassert( isReading() ); diff --git a/code/nel/src/misc/bit_mem_stream.cpp b/code/nel/src/misc/bit_mem_stream.cpp index c050d9c61..007b95cbc 100644 --- a/code/nel/src/misc/bit_mem_stream.cpp +++ b/code/nel/src/misc/bit_mem_stream.cpp @@ -599,7 +599,7 @@ void CBitMemStream::append( const CBitMemStream& newBits ) /* * Serial bitmemstream */ -void CBitMemStream::serialMemStream(CBitMemStream &b) +void CBitMemStream::serialMemStream(CMemStream &b) { #ifdef LOG_ALL_TRAFFIC sint32 bitpos = getPosInBit(); diff --git a/code/nel/src/misc/bitmap_jpeg.cpp b/code/nel/src/misc/bitmap_jpeg.cpp index 835110d86..a4eaaa0b9 100644 --- a/code/nel/src/misc/bitmap_jpeg.cpp +++ b/code/nel/src/misc/bitmap_jpeg.cpp @@ -109,7 +109,7 @@ static void jpgDecompressSkip(j_decompress_ptr cinfo, long num_bytes) } } -static void jpgDecompressTerm(j_decompress_ptr cinfo) +static void jpgDecompressTerm(j_decompress_ptr /* cinfo */) { } diff --git a/code/nel/src/misc/co_task.cpp b/code/nel/src/misc/co_task.cpp index 1880be06c..c66941a40 100644 --- a/code/nel/src/misc/co_task.cpp +++ b/code/nel/src/misc/co_task.cpp @@ -237,12 +237,15 @@ namespace NLMISC _PImpl = new TCoTaskData(this); // _PImpl->_TaskThreadId = 0; // _PImpl->_ParentThreadId = 0; + nlunreferenced(stackSize); #else //NL_USE_THREAD_COTASK // allocate platform specific data storage _PImpl = new TCoTaskData; + nlunreferenced(stackSize); #if defined (NL_OS_WINDOWS) _PImpl->_Fiber = NULL; _PImpl->_ParentFiber = NULL; + nlunreferenced(stackSize); #elif defined(NL_OS_UNIX) // allocate the stack _PImpl->_Stack = new uint8[stackSize]; diff --git a/code/nel/src/misc/command.cpp b/code/nel/src/misc/command.cpp index 80d074386..f2b422d69 100644 --- a/code/nel/src/misc/command.cpp +++ b/code/nel/src/misc/command.cpp @@ -650,6 +650,9 @@ ICommand *CCommandRegistry::getCommand(const std::string &commandName) NLMISC_CATEGORISED_COMMAND(nel,help,"display help on a specific variable/commands or on all variables and commands", "[|]") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); // nlassert (_Commands != NULL); // make sure we have a valid number of parameters diff --git a/code/nel/src/misc/common.cpp b/code/nel/src/misc/common.cpp index 6d37c19ab..d89708c4e 100644 --- a/code/nel/src/misc/common.cpp +++ b/code/nel/src/misc/common.cpp @@ -373,6 +373,10 @@ uint32 humanReadableToBytes (const string &str) NLMISC_CATEGORISED_COMMAND(nel,btohr, "Convert a bytes number into an human readable number", "") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if (args.size() != 1) return false; @@ -384,6 +388,10 @@ NLMISC_CATEGORISED_COMMAND(nel,btohr, "Convert a bytes number into an human read NLMISC_CATEGORISED_COMMAND(nel,hrtob, "Convert a human readable number into a bytes number", "
") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if (args.size() != 1) return false; @@ -446,6 +454,10 @@ uint32 fromHumanReadable (const std::string &str) NLMISC_CATEGORISED_COMMAND(nel,stohr, "Convert a second number into an human readable time", "") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if (args.size() != 1) return false; @@ -829,6 +841,7 @@ int nlfseek64( FILE *stream, sint64 offset, int origin ) return fsetpos (stream, &pos64); #else // NL_OS_WINDOWS + // TODO: to fix for Linux and Mac OS X // This code doesn't work under windows : fseek() implementation uses a signed 32 bits offset. What ever we do, it can't seek more than 2 Go. // For the moment, i don't know if it works under linux for seek of more than 2 Go. @@ -871,6 +884,9 @@ sint64 nlftell64(FILE *stream) } else return -1; #else + nlunreferenced(stream); + + // TODO: implement for Linux and Mac OS X nlerror("Not implemented"); return -1; #endif @@ -885,9 +901,14 @@ sint64 nlftell64(FILE *stream) NLMISC_CATEGORISED_COMMAND(nel, sleep, "Freeze the service for N seconds (for debug purpose)", "") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if(args.size() != 1) return false; - sint32 n = atoi (args[0].c_str()); + sint32 n; + fromString(args[0], n); log.displayNL ("Sleeping during %d seconds", n); @@ -897,6 +918,10 @@ NLMISC_CATEGORISED_COMMAND(nel, sleep, "Freeze the service for N seconds (for de NLMISC_CATEGORISED_COMMAND(nel, system, "Execute the command line using system() function call (wait until the end of the command)", "") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if(args.size() != 1) return false; string cmd = args[0]; @@ -915,6 +940,10 @@ NLMISC_CATEGORISED_COMMAND(nel, system, "Execute the command line using system() NLMISC_CATEGORISED_COMMAND(nel, launchProgram, "Execute the command line using launcProgram() function call (launch in background task without waiting the end of the execution)", " ") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if(args.size() != 2) return false; string cmd = args[0]; @@ -927,6 +956,10 @@ NLMISC_CATEGORISED_COMMAND(nel, launchProgram, "Execute the command line using l NLMISC_CATEGORISED_COMMAND(nel, killProgram, "kill a program given the pid", "") { + nlunreferenced(rawCommandString); + nlunreferenced(quiet); + nlunreferenced(human); + if(args.size() != 1) return false; uint32 pid; fromString(args[0], pid); @@ -1030,6 +1063,9 @@ bool openDoc (const char *document) } else return true; +#else + // TODO: implement for Linux and Mac OS X + nlunreferenced(document); #endif // NL_OS_WINDOWS return false; } From 77c3ccb1e14c0f1520cc132f99d2bf57cd9b6976 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 11:54:20 +0200 Subject: [PATCH 06/66] Changed: #1459 Simplify the sound group controller interface --- code/nel/include/nel/sound/group_controller.h | 27 +++++++++---------- .../include/nel/sound/u_group_controller.h | 15 ++++------- .../samples/sound/stream_file/stream_file.cpp | 6 ++--- .../stream_ogg_vorbis/stream_ogg_vorbis.cpp | 6 ++--- code/nel/src/sound/group_controller.cpp | 6 ++--- code/nel/src/sound/group_controller_root.cpp | 13 ++++++--- code/ryzom/client/src/sound_manager.cpp | 10 +++++-- code/ryzom/client/src/sound_manager.h | 5 +++- 8 files changed, 47 insertions(+), 41 deletions(-) diff --git a/code/nel/include/nel/sound/group_controller.h b/code/nel/include/nel/sound/group_controller.h index 08d474129..25b7034b6 100644 --- a/code/nel/include/nel/sound/group_controller.h +++ b/code/nel/include/nel/sound/group_controller.h @@ -57,9 +57,11 @@ public: private: CGroupController *m_Parent; std::map m_Children; - - float m_DevGain; - float m_UserGain; + + /// Gain as set by the interface + float m_Gain; + + /// Gain including parent gain float m_FinalGain; int m_NbSourcesInclChild; @@ -70,27 +72,22 @@ public: /// \name UGroupController //@{ - virtual void setDevGain(float gain) { NLMISC::clamp(gain, 0.0f, 1.0f); m_DevGain = gain; updateSourceGain(); } - virtual float getDevGain() { return m_DevGain; } - - virtual void setUserGain(float gain) { NLMISC::clamp(gain, 0.0f, 1.0f); m_UserGain = gain; updateSourceGain(); } - virtual float getUserGain() { return m_UserGain; } - - virtual void setGain(float devGain, float userGain) { NLMISC::clamp(devGain, 0.0f, 1.0f); NLMISC::clamp(userGain, 0.0f, 1.0f); m_DevGain = devGain; m_UserGain = userGain; updateSourceGain(); } + virtual void setGain(float gain) { NLMISC::clamp(gain, 0.0f, 1.0f); if (m_Gain != gain) { m_Gain = gain; updateSourceGain(); } } + virtual float getGain() { return m_Gain; } //@} - + inline float getFinalGain() const { return m_FinalGain; } - + void addSource(CSourceCommon *source); void removeSource(CSourceCommon *source); - + virtual std::string getPath(); - + protected: virtual ~CGroupController(); // subnodes can only be deleted by the root private: - inline float calculateTotalGain() { return m_DevGain * m_UserGain; } + inline float calculateTotalGain() { return m_Gain; } virtual void calculateFinalGain(); virtual void increaseSources(); virtual void decreaseSources(); diff --git a/code/nel/include/nel/sound/u_group_controller.h b/code/nel/include/nel/sound/u_group_controller.h index 54a28b835..5aadeb25c 100644 --- a/code/nel/include/nel/sound/u_group_controller.h +++ b/code/nel/include/nel/sound/u_group_controller.h @@ -35,9 +35,9 @@ // Project includes -#define NLSOUND_SHEET_V1_DEFAULT_SOUND_GROUP_CONTROLLER "effects" -#define NLSOUND_SHEET_V1_DEFAULT_SOUND_MUSIC_GROUP_CONTROLLER "music" -#define NLSOUND_SHEET_V1_DEFAULT_SOUND_STREAM_GROUP_CONTROLLER "dialog" +#define NLSOUND_SHEET_V1_DEFAULT_SOUND_GROUP_CONTROLLER "sound:effects:game" +#define NLSOUND_SHEET_V1_DEFAULT_SOUND_MUSIC_GROUP_CONTROLLER "sound:music:game" +#define NLSOUND_SHEET_V1_DEFAULT_SOUND_STREAM_GROUP_CONTROLLER "sound:dialog:game" namespace NLSOUND { @@ -50,13 +50,8 @@ namespace NLSOUND { class UGroupController { public: - virtual void setDevGain(float gain) = 0; - virtual float getDevGain() = 0; - - virtual void setUserGain(float gain) = 0; - virtual float getUserGain() = 0; - - virtual void setGain(float devGain, float userGain) = 0; + virtual void setGain(float gain) = 0; + virtual float getGain() = 0; protected: virtual ~UGroupController() { } diff --git a/code/nel/samples/sound/stream_file/stream_file.cpp b/code/nel/samples/sound/stream_file/stream_file.cpp index 2ace9dc6b..623ee4ff0 100644 --- a/code/nel/samples/sound/stream_file/stream_file.cpp +++ b/code/nel/samples/sound/stream_file/stream_file.cpp @@ -106,7 +106,7 @@ static void initSample() // s_Source->setSourceRelativeMode(true); // s_Source->setPitch(2.0f); - s_GroupController = s_AudioMixer->getGroupController("dialog"); + s_GroupController = s_AudioMixer->getGroupController("sound:dialog"); } static void runSample() @@ -129,10 +129,10 @@ static void runSample() #endif { case '+': - s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); + s_GroupController->setGain(s_GroupController->getGain() + 0.1f); break; case '-': - s_GroupController->setUserGain(s_GroupController->getUserGain() - 0.1f); + s_GroupController->setGain(s_GroupController->getGain() - 0.1f); break; case 'x': s_Source->stop(); diff --git a/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp b/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp index b3645913c..e0f0df705 100644 --- a/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp +++ b/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp @@ -100,7 +100,7 @@ static void initSample() s_StreamSource->setFormat(s_AudioDecoder->getChannels(), s_AudioDecoder->getBitsPerSample(), (uint32)s_AudioDecoder->getSamplesPerSec()); //s_StreamSource->setPitch(2.0f); - s_GroupController = s_AudioMixer->getGroupController("dialog"); + s_GroupController = s_AudioMixer->getGroupController("sound:dialog"); } //CMutex *s_Mutex = NULL; @@ -154,10 +154,10 @@ static void runSample() #endif { case '+': - s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); + s_GroupController->setGain(s_GroupController->getGain() + 0.1f); break; case '-': - s_GroupController->setUserGain(s_GroupController->getUserGain() - 0.1f); + s_GroupController->setGain(s_GroupController->getGain() - 0.1f); break; default: return; diff --git a/code/nel/src/sound/group_controller.cpp b/code/nel/src/sound/group_controller.cpp index fef67a01b..d01e29252 100644 --- a/code/nel/src/sound/group_controller.cpp +++ b/code/nel/src/sound/group_controller.cpp @@ -42,7 +42,7 @@ using namespace std; namespace NLSOUND { CGroupController::CGroupController(CGroupController *parent) : - m_Parent(parent), m_DevGain(1.0f), m_UserGain(1.0f), m_NbSourcesInclChild(0) + m_Parent(parent), m_Gain(1.0f), m_NbSourcesInclChild(0) { } @@ -81,9 +81,7 @@ std::string CGroupController::getPath() // overridden by root if (it->second == this) { const std::string &name = it->first; - std::string returnPath = m_Parent->getPath() + "/" + name; - if (returnPath[0] == '/') - returnPath = returnPath.substr(1); + std::string returnPath = m_Parent->getPath() + ":" + name; return returnPath; } } diff --git a/code/nel/src/sound/group_controller_root.cpp b/code/nel/src/sound/group_controller_root.cpp index f49a40fff..f1344e195 100644 --- a/code/nel/src/sound/group_controller_root.cpp +++ b/code/nel/src/sound/group_controller_root.cpp @@ -39,6 +39,8 @@ using namespace std; // using namespace NLMISC; +#define NLSOUND_GROUP_CONTROLLER_ROOT_PATH "sound" + namespace NLSOUND { CGroupControllerRoot::CGroupControllerRoot() : CGroupController(NULL) @@ -53,7 +55,8 @@ CGroupControllerRoot::~CGroupControllerRoot() std::string CGroupControllerRoot::getPath() { - return ""; + // The root node is always called sound + return NLSOUND_GROUP_CONTROLLER_ROOT_PATH; } void CGroupControllerRoot::calculateFinalGain() @@ -78,9 +81,13 @@ void CGroupControllerRoot::decreaseSources() CGroupController *CGroupControllerRoot::getGroupController(const std::string &path) { std::vector pathNodes; - NLMISC::splitString(NLMISC::toLower(path), "/", pathNodes); + NLMISC::splitString(NLMISC::toLower(path), ":", pathNodes); CGroupController *active = this; - for (std::vector::iterator it(pathNodes.begin()), end(pathNodes.end()); it != end; ++it) + if (pathNodes[0] != NLSOUND_GROUP_CONTROLLER_ROOT_PATH) + { + nlerror("Root node for group controller must always be 'sound', invalid group '%s' requested", path.c_str()); + } + for (std::vector::iterator it(pathNodes.begin() + 1), end(pathNodes.end()); it != end; ++it) { if (!(*it).empty()) { diff --git a/code/ryzom/client/src/sound_manager.cpp b/code/ryzom/client/src/sound_manager.cpp index a82e4b422..182a28cb1 100644 --- a/code/ryzom/client/src/sound_manager.cpp +++ b/code/ryzom/client/src/sound_manager.cpp @@ -107,6 +107,8 @@ enum TFilterMapping //----------------------------------------------- CSoundManager::CSoundManager(IProgressCallback * /* progressCallBack */) : _AudioMixer(NULL), + _GroupControllerEffects(NULL), + _GroupControllerEffectsGame(NULL), _EnvSoundRoot(NULL), _UserEntitySoundLevel(1.0f), _Sources(NULL) @@ -139,6 +141,7 @@ CSoundManager::~CSoundManager() NL3D::UParticleSystemSound::setPSSound(NULL); _GroupControllerEffects = NULL; + _GroupControllerEffectsGame = NULL; // free the audio mixer (and delete all sources) delete _AudioMixer; @@ -407,6 +410,7 @@ void CSoundManager::reset () NL3D::UParticleSystemSound::setPSSound(NULL); _GroupControllerEffects = NULL; + _GroupControllerEffectsGame = NULL; delete _AudioMixer; _AudioMixer = NULL; @@ -482,7 +486,8 @@ void CSoundManager::init(IProgressCallback *progressCallBack) new CSoundAnimManager(_AudioMixer); // get the controller group for effects - _GroupControllerEffects = _AudioMixer->getGroupController("effects"); + _GroupControllerEffects = _AudioMixer->getGroupController("sound:effects"); + _GroupControllerEffectsGame = _AudioMixer->getGroupController("sound:effects:game"); // restore the volume SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume); @@ -1543,7 +1548,8 @@ void CSoundManager::updateVolume() _AudioMixer->setEventMusicVolume(_GameMusicVolume); // update sfx volume - _GroupControllerEffects->setGain(_FadeSFXVolume, _SFXVolume); + _GroupControllerEffects->setGain(_SFXVolume); + _GroupControllerEffectsGame->setGain(_FadeSFXVolume); } } diff --git a/code/ryzom/client/src/sound_manager.h b/code/ryzom/client/src/sound_manager.h index e5db85648..80401ea57 100644 --- a/code/ryzom/client/src/sound_manager.h +++ b/code/ryzom/client/src/sound_manager.h @@ -332,9 +332,12 @@ private: /// Pointer on the audio mixer object NLSOUND::UAudioMixer *_AudioMixer; - /// The root effects group controller for volume settings + /// The root effects group controller for effects volume settings by the user NLSOUND::UGroupController *_GroupControllerEffects; + /// The root effects group controller for effects fading by the game + NLSOUND::UGroupController *_GroupControllerEffectsGame; + /// Pointer on the root of the environmental sounds tree (if any) NLSOUND::UEnvSound *_EnvSoundRoot; From 45a857b564c8aaefd4f6852c10cfe64bf4852be3 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 13:59:24 +0200 Subject: [PATCH 07/66] Changed: #1459 Reserve functional group controller node names --- .../include/nel/sound/group_controller_root.h | 1 + code/nel/src/sound/group_controller_root.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/code/nel/include/nel/sound/group_controller_root.h b/code/nel/include/nel/sound/group_controller_root.h index 2cc86f5b3..2081fa28a 100644 --- a/code/nel/include/nel/sound/group_controller_root.h +++ b/code/nel/include/nel/sound/group_controller_root.h @@ -59,6 +59,7 @@ protected: virtual void calculateFinalGain(); virtual void increaseSources(); virtual void decreaseSources(); + static bool isReservedName(const std::string &nodeName); }; /* class CGroupControllerRoot */ diff --git a/code/nel/src/sound/group_controller_root.cpp b/code/nel/src/sound/group_controller_root.cpp index f1344e195..7ba7173e4 100644 --- a/code/nel/src/sound/group_controller_root.cpp +++ b/code/nel/src/sound/group_controller_root.cpp @@ -78,6 +78,18 @@ void CGroupControllerRoot::decreaseSources() --m_NbSourcesInclChild; } +bool CGroupControllerRoot::isReservedName(const std::string &nodeName) +{ + // These node names are reserved, in case these category controllers can be integrated with CDB. + // I do not forsee any functionality for changing environment effect settings for entire categories. + // The nodeName parameter is already lowercase, see CGroupControllerRoot::getGroupController. + if (nodeName == NLSOUND_GROUP_CONTROLLER_ROOT_PATH) return true; // Root node name can only used by root. + if (nodeName == "gain") return true; + if (nodeName == "pitch") return true; + if (nodeName == "enable" || nodeName == "enabled") return true; + return true; +} + CGroupController *CGroupControllerRoot::getGroupController(const std::string &path) { std::vector pathNodes; @@ -91,6 +103,10 @@ CGroupController *CGroupControllerRoot::getGroupController(const std::string &pa { if (!(*it).empty()) { + if (isReservedName(*it)) + { + nlerror("Attempt to use reserved node name '%s' in group controller path '%s'", (*it).c_str(), path.c_str()); + } std::map::iterator found = active->m_Children.find(*it); if (found == active->m_Children.end()) { From 0e5d7137d6a2bc00e52cb64866814530f3f2a535 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 14:15:04 +0200 Subject: [PATCH 08/66] Fixed: Typo --- code/nel/src/sound/group_controller_root.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/nel/src/sound/group_controller_root.cpp b/code/nel/src/sound/group_controller_root.cpp index 7ba7173e4..0f1c58e63 100644 --- a/code/nel/src/sound/group_controller_root.cpp +++ b/code/nel/src/sound/group_controller_root.cpp @@ -87,7 +87,7 @@ bool CGroupControllerRoot::isReservedName(const std::string &nodeName) if (nodeName == "gain") return true; if (nodeName == "pitch") return true; if (nodeName == "enable" || nodeName == "enabled") return true; - return true; + return false; } CGroupController *CGroupControllerRoot::getGroupController(const std::string &path) From eb293f5325c0054becd6cc1643db95fddc30e9c9 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 23:29:18 +0200 Subject: [PATCH 09/66] Fixed: Warnings --- code/ryzom/client/src/sound_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/ryzom/client/src/sound_manager.cpp b/code/ryzom/client/src/sound_manager.cpp index 182a28cb1..4d8827875 100644 --- a/code/ryzom/client/src/sound_manager.cpp +++ b/code/ryzom/client/src/sound_manager.cpp @@ -110,8 +110,8 @@ CSoundManager::CSoundManager(IProgressCallback * /* progressCallBack */) _GroupControllerEffects(NULL), _GroupControllerEffectsGame(NULL), _EnvSoundRoot(NULL), - _UserEntitySoundLevel(1.0f), - _Sources(NULL) + _Sources(NULL), + _UserEntitySoundLevel(1.0f) { _EnableBackgroundMusicAtTime= 0; _GameMusicVolume= 1.f; @@ -747,7 +747,7 @@ nldebug("nb sources = %d", _Sources.size() ); { if ( (*it).second == sourceId ) { - (*it).second = NULL; + (*it).second = 0; // itOld = it; // ++it; From f815bb254929582863a4b6afaed151747300880d Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 13 Apr 2012 23:30:35 +0200 Subject: [PATCH 10/66] Fixed: Crash on exit caused by incomplete music channel reset --- code/nel/include/nel/sound/audio_mixer_user.h | 2 ++ code/nel/src/sound/audio_mixer_user.cpp | 30 ++++++++++++++++++- code/nel/src/sound/source_music_channel.cpp | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/code/nel/include/nel/sound/audio_mixer_user.h b/code/nel/include/nel/sound/audio_mixer_user.h index 1316fe34a..9c9fd5c86 100644 --- a/code/nel/include/nel/sound/audio_mixer_user.h +++ b/code/nel/include/nel/sound/audio_mixer_user.h @@ -230,6 +230,8 @@ public: virtual uint getSourcesInstanceCount() const { return (uint)_Sources.size(); } /// Return the number of playing sources (slow) virtual uint getPlayingSourcesCount() const; + uint countPlayingSimpleSources() const; // debug + uint countSimpleSources() const; // debug /// Return the number of available tracks virtual uint getAvailableTracksCount() const; /// Return the number of used tracks diff --git a/code/nel/src/sound/audio_mixer_user.cpp b/code/nel/src/sound/audio_mixer_user.cpp index 8bec4442c..1a6c2d322 100644 --- a/code/nel/src/sound/audio_mixer_user.cpp +++ b/code/nel/src/sound/audio_mixer_user.cpp @@ -221,6 +221,7 @@ void CAudioMixerUser::writeProfile(std::string& out) */ out += "Sound mixer: \n"; out += "\tPlaying sources: " + toString (getPlayingSourcesCount()) + " \n"; + out += "\tPlaying simple sources: " + toString(countPlayingSimpleSources()) + " / " + toString(countSimpleSources()) + " \n"; out += "\tAvailable tracks: " + toString (getAvailableTracksCount()) + " \n"; out += "\tUsed tracks: " + toString (getUsedTracksCount()) + " \n"; // out << "\tMuted sources: " << nb << " \n"; @@ -270,7 +271,8 @@ void CAudioMixerUser::reset() _SourceWaitingForPlay.clear(); - _MusicChannelFaders->reset(); + for (uint i = 0; i < _NbMusicChannelFaders; ++i) + _MusicChannelFaders[i].reset(); // Stop tracks uint i; @@ -2173,6 +2175,32 @@ uint CAudioMixerUser::getPlayingSourcesCount() const return _PlayingSources; } + +// ****************************************************************** + +uint CAudioMixerUser::countPlayingSimpleSources() const +{ + uint count = 0; + for (TSourceContainer::const_iterator it(_Sources.begin()), end(_Sources.end()); it != end; ++it) + { + if ((*it)->getType() == CSourceCommon::SOURCE_SIMPLE && (*it)->isPlaying()) + ++count; + } + return count; +} + +uint CAudioMixerUser::countSimpleSources() const +{ + uint count = 0; + for (TSourceContainer::const_iterator it(_Sources.begin()), end(_Sources.end()); it != end; ++it) + { + if ((*it)->getType() == CSourceCommon::SOURCE_SIMPLE) + ++count; + } + return count; +} + + // ****************************************************************** uint CAudioMixerUser::getAvailableTracksCount() const diff --git a/code/nel/src/sound/source_music_channel.cpp b/code/nel/src/sound/source_music_channel.cpp index 677370dd3..34735f113 100644 --- a/code/nel/src/sound/source_music_channel.cpp +++ b/code/nel/src/sound/source_music_channel.cpp @@ -48,6 +48,7 @@ CSourceMusicChannel::CSourceMusicChannel() : m_Source(NULL), m_Gain(1.0f) CSourceMusicChannel::~CSourceMusicChannel() { + nlassert(!m_Source); delete m_Source; m_Source = NULL; } From 0320da86a6c15af51f375a6e3b84143ab6216596 Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 18 Apr 2012 11:07:01 -0500 Subject: [PATCH 11/66] Changed: Used a Regex to workaround the colon project name issue for VS10. --- code/CMakeModules/nel.cmake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index bd92e743e..846ba4039 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -64,9 +64,10 @@ ENDMACRO(NL_TARGET_DRIVER) # Argument: ### MACRO(NL_DEFAULT_PROPS name label) - IF(NOT MSVC10) - SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${label}) - ENDIF(NOT MSVC10) + # Note: This is just a workaround for a CMake bug generating VS10 files with a colon in the project name. + # CMake Bug ID: http://www.cmake.org/Bug/view.php?id=11819 + STRING(REGEX REPLACE "\\:" " -" proj_label ${label}) + SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${proj_label}) GET_TARGET_PROPERTY(type ${name} TYPE) IF(${type} STREQUAL SHARED_LIBRARY) # Set versions only if target is a shared library From f809ba6ca3d36f4f342763c7a1acfa1750a1fe88 Mon Sep 17 00:00:00 2001 From: sfb Date: Fri, 20 Apr 2012 12:46:18 -0500 Subject: [PATCH 12/66] Changed: #1306 Implemented core "open" action to load a form from an arbitrary location. --- .../georges_editor/georges_editor_form.cpp | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp index 252d7fd7e..3b6c629a8 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp @@ -112,24 +112,9 @@ namespace Plugin void GeorgesEditorForm::open() { - /*qDebug() << "GeorgesEditorForm::open()"; - if (!m_dockedWidgets.size()) - { - m_dockedWidgets.append(new CGeorgesTreeViewDialog(m_mainDock)); - m_mainDock->addDockWidget(Qt::RightDockWidgetArea, m_dockedWidgets.last()); - } - else - { - m_dockedWidgets.append(new CGeorgesTreeViewDialog(m_mainDock)); - Q_ASSERT(m_dockedWidgets.size() > 1); - m_mainDock->tabifyDockWidget(m_dockedWidgets.at(m_dockedWidgets.size() - 2), m_dockedWidgets.last()); - }*/ - - // TODO: FileDialog & loadFile(); - //m_mainDock->addDockWidget(Qt::TopDockWidgetArea, new CGeorgesTreeViewDialog(m_mainDock, true)); - //m_mainDock->addDockWidget(Qt::LeftDockWidgetArea, new CGeorgesTreeViewDialog(m_mainDock, true)); - //QString fileName = QFileDialog::getOpenFileName(); - //loadFile(fileName); + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Form")); + if(!fileName.isNull()) + loadFile(fileName); } void GeorgesEditorForm::newFile() From f3363e0aebe0d5a5bace434e4e9d53ace67280ae Mon Sep 17 00:00:00 2001 From: sfb Date: Fri, 20 Apr 2012 15:40:02 -0500 Subject: [PATCH 13/66] Changed: #1306 Added undo stack deeper (for later) and began adding form context menus proof-of-concept. --- .../georges_editor/georges_editor_form.cpp | 2 + .../georges_treeview_dialog.cpp | 53 +++++++++++++++++++ .../georges_editor/georges_treeview_dialog.h | 10 ++++ 3 files changed, 65 insertions(+) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp index 3b6c629a8..0cc5b9542 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp @@ -176,6 +176,7 @@ namespace Plugin if (!m_dockedWidgets.size()) { CGeorgesTreeViewDialog *dock = new CGeorgesTreeViewDialog(m_mainDock); + dock->setUndoStack(m_undoStack); m_lastActiveDock = dock; m_dockedWidgets.append(dock); @@ -197,6 +198,7 @@ namespace Plugin } } CGeorgesTreeViewDialog *dock = new CGeorgesTreeViewDialog(m_mainDock); + dock->setUndoStack(m_undoStack); m_dockedWidgets.append(dock); connect(m_dockedWidgets.last(), SIGNAL(closing()), diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp index 13b0dab03..ac72cd747 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp @@ -21,6 +21,7 @@ #include #include #include +#include // NeL includes #include @@ -65,6 +66,10 @@ namespace Plugin FormDelegate *formdelegate = new FormDelegate(this); m_ui.treeView->setItemDelegateForColumn(1, formdelegate); + // Set up custom context menu. + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); + connect(m_ui.treeView, SIGNAL(doubleClicked (QModelIndex)), this, SLOT(doubleClicked (QModelIndex))); connect(m_ui.checkBoxParent, SIGNAL(toggled(bool)), @@ -385,4 +390,52 @@ namespace Plugin } } + void CGeorgesTreeViewDialog::showContextMenu(const QPoint &pos) + { + QMenu contextMenu; + QPoint globalPos = this->mapToGlobal(pos); + + // Fisrt we're going to see if we've right clicked on a new item and select it. + QModelIndex &index = this->m_ui.treeView->currentIndex(); + + if(!index.isValid()) + return; + + CGeorgesFormProxyModel * mp = dynamic_cast(m_ui.treeView->model()); + CGeorgesFormModel *m = dynamic_cast(mp->sourceModel()); + QModelIndex sourceIndex = mp->mapToSource(index); + + if (m) + { + + CFormItem *item = m->getItem(sourceIndex); + + if ((item->parent() && item->parent()->data(0) == "parents") || item->data(0) == "parents") + contextMenu.addAction("Add parent..."); + else if(item->getFormElm()->isArray()) + contextMenu.addAction("Add array entry..."); + else if(item->getFormElm()->isStruct()) + contextMenu.addAction("Add element..."); + else if(item->getFormElm()->isAtom() && item->valueFrom() == NLGEORGES::UFormElm::ValueForm) + contextMenu.addAction("Revert to parent/default..."); + else if(item->getFormElm()->isAtom() && item->valueFrom() == NLGEORGES::UFormElm::ValueParentForm) + contextMenu.addAction("Override parent/default value..."); + else + contextMenu.addAction("Add element..."); + + QAction *selectedItem = contextMenu.exec(globalPos); + if(selectedItem) + { + if(selectedItem->text() == "Add parent...") + { + QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select parent sheets...")); + if(!fileNames.isEmpty()) + { + // add some parents. + } + } + } + } + } + } /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h index 4992c9b23..8c2db3d47 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h @@ -22,6 +22,9 @@ // Qt includes #include +#include +#include + // STL includes @@ -60,6 +63,10 @@ namespace Plugin QTabWidget* tabWidget() { return m_ui.treeViewTabWidget; } + void setUndoStack(QUndoStack *stack) { + m_undoStack = stack; + } + QString loadedForm; protected: @@ -75,6 +82,7 @@ namespace Plugin void loadFormIntoDialog(CForm *form = 0); void modifiedFile( ); void checkVisibility(bool); + void showContextMenu(const QPoint &pos); private Q_SLOTS: void doubleClicked ( const QModelIndex & index ); @@ -87,6 +95,8 @@ namespace Plugin UForm *m_form; CGeorges *m_georges; + QUndoStack *m_undoStack; + bool m_modified; }; /* CGeorgesTreeViewDialog */ From d0e98454cf63c945d2fd5c626f7f74abf4e2e90b Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Mon, 23 Apr 2012 20:30:57 +0300 Subject: [PATCH 14/66] Changed: #1306 Improved ui of geqt --- .../src/plugins/georges_editor/georges_dirtree_form.ui | 3 +++ .../src/plugins/georges_editor/georges_treeview_form.ui | 3 +++ 2 files changed, 6 insertions(+) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_form.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_form.ui index 4a429af1f..e14857e89 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_form.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_form.ui @@ -44,6 +44,9 @@ 0 + + true + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_form.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_form.ui index 183b16118..8d53bfdd6 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_form.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_form.ui @@ -63,6 +63,9 @@ 0 + + true + From c032c58b43678ba697d4969dff4faf895a26d2f3 Mon Sep 17 00:00:00 2001 From: sfb Date: Thu, 26 Apr 2012 13:05:53 -0500 Subject: [PATCH 15/66] Changed: #1306 Implemented add/removing parent sheets, moved everything out of Plugin and into GeorgesQt namespace to eliminate ambiguity with other plugins. --- .../georges_editor/expandable_headerview.cpp | 2 +- .../georges_editor/expandable_headerview.h | 2 +- .../plugins/georges_editor/formdelegate.cpp | 4 +- .../src/plugins/georges_editor/formdelegate.h | 2 +- .../src/plugins/georges_editor/formitem.cpp | 2 +- .../src/plugins/georges_editor/formitem.h | 2 +- .../src/plugins/georges_editor/georges.cpp | 4 +- .../src/plugins/georges_editor/georges.h | 4 +- .../georges_editor/georges_dirtree_dialog.cpp | 4 +- .../georges_editor/georges_dirtree_dialog.h | 4 +- .../georges_editor/georges_editor_constants.h | 4 +- .../georges_editor/georges_editor_form.cpp | 4 +- .../georges_editor/georges_editor_form.h | 4 +- .../georges_editor/georges_editor_plugin.cpp | 4 +- .../georges_editor/georges_editor_plugin.h | 4 +- .../georges_filesystem_model.cpp | 4 +- .../georges_editor/georges_filesystem_model.h | 4 +- .../georges_treeview_dialog.cpp | 134 ++++++++++++++++-- .../georges_editor/georges_treeview_dialog.h | 9 +- .../georges_editor/georgesform_model.cpp | 31 +++- .../georges_editor/georgesform_model.h | 10 +- .../georgesform_proxy_model.cpp | 4 +- .../georges_editor/georgesform_proxy_model.h | 4 +- 23 files changed, 192 insertions(+), 58 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.cpp index 7ae482824..2967be435 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.cpp @@ -22,7 +22,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { ExpandableHeaderView::ExpandableHeaderView(Qt::Orientation orientation, QWidget * parent) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.h index 596bf5ba1..f7f26eafc 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/expandable_headerview.h @@ -20,7 +20,7 @@ // Qt includes #include -namespace Plugin +namespace GeorgesQt { class ExpandableHeaderView : public QHeaderView { diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.cpp index 4d04bc6b5..be358d065 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.cpp @@ -37,7 +37,7 @@ #include "georgesform_proxy_model.h" #include "formitem.h" -namespace Plugin +namespace GeorgesQt { FormDelegate::FormDelegate(QObject *parent) @@ -275,4 +275,4 @@ namespace Plugin QRect r = option.rect; editor->setGeometry(r); } -} /* namespace Plugin */ +} /* namespace GeorgesQt */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.h index a309da1fc..486308536 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formdelegate.h @@ -19,7 +19,7 @@ #include -namespace Plugin +namespace GeorgesQt { class FormDelegate : public QStyledItemDelegate diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.cpp index 205e18a52..68f29064d 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.cpp @@ -23,7 +23,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { CFormItem::CFormItem(NLGEORGES::UFormElm* elm, const QList &data, CFormItem *parent, diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.h index b85b12275..80efce5d5 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/formitem.h @@ -24,7 +24,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { class CFormItem diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.cpp index b93f93ec4..50e007d90 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.cpp @@ -28,7 +28,7 @@ using namespace NLGEORGES; -namespace Plugin +namespace GeorgesQt { CGeorges::CGeorges(): FormLoader(0) @@ -61,4 +61,4 @@ namespace Plugin return type; } -} /* namespace Plugin */ +} /* namespace GeorgesQt */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.h index eb9a6b7da..6d7455d3b 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges.h @@ -38,7 +38,7 @@ namespace NLGEORGES using namespace NLGEORGES; -namespace Plugin +namespace GeorgesQt { /** @@ -64,6 +64,6 @@ namespace Plugin };/* class CGeorges */ -} /* namespace Plugin */ +} /* namespace GeorgesQt */ #endif // GEORGES_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.cpp index de7a105ab..163ec7877 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.cpp @@ -23,7 +23,7 @@ // NeL includes -namespace Plugin +namespace GeorgesQt { CGeorgesDirTreeDialog::CGeorgesDirTreeDialog(QString ldPath, QWidget *parent) @@ -109,4 +109,4 @@ void CGeorgesDirTreeDialog::ldPathChanged(QString path) } } -} /* namespace NLQT */ \ No newline at end of file +} /* namespace GeorgesQt */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.h index fa783bca0..dc717617e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_dirtree_dialog.h @@ -28,7 +28,7 @@ #include "ui_georges_dirtree_form.h" #include "georges_filesystem_model.h" -namespace Plugin +namespace GeorgesQt { class CGeorgesDirTreeDialog: public QDockWidget @@ -57,6 +57,6 @@ private Q_SLOTS: }; /* CGEorgesDirTreeDialog */ -} /* namespace NLQT */ +} /* namespace GeorgesQt */ #endif // GEORGES_DIRTREE_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_constants.h index bb9fe3306..cccede9fc 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_constants.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_constants.h @@ -17,7 +17,7 @@ #ifndef GEORGES_EDITOR_CONSTANTS_H #define GEORGES_EDITOR_CONSTANTS_H -namespace Plugin +namespace GeorgesQt { namespace Constants { @@ -26,6 +26,6 @@ const char * const GEORGES_EDITOR_SECTION = "GeorgesEditor"; } // namespace Constants -} // namespace Plugin +} // namespace GeorgesQt #endif // GEORGES_EDITOR_CONSTANTS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp index 0cc5b9542..a9666c8db 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp @@ -33,7 +33,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { GeorgesEditorForm::GeorgesEditorForm(QWidget *parent) @@ -271,4 +271,4 @@ namespace Plugin } } } -} /* namespace Plugin */ +} /* namespace GeorgesQt */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.h index 6b270ca3d..c991f8b9f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.h @@ -23,7 +23,7 @@ // Qt includes #include -namespace Plugin +namespace GeorgesQt { class CGeorgesDirTreeDialog; @@ -70,6 +70,6 @@ private: CGeorgesTreeViewDialog *m_lastActiveDock; }; /* class GeorgesEditorForm */ -} /* namespace Plugin */ +} /* namespace GeorgesQt */ #endif // GEORGES_EDITOR_FORM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.cpp index 199bc20ca..7dd0be5cd 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.cpp @@ -27,7 +27,7 @@ // Qt includes #include -namespace Plugin +namespace GeorgesQt { GeorgesEditorPlugin::~GeorgesEditorPlugin() @@ -97,4 +97,4 @@ QWidget *GeorgesEditorContext::widget() } -Q_EXPORT_PLUGIN(Plugin::GeorgesEditorPlugin) \ No newline at end of file +Q_EXPORT_PLUGIN(GeorgesQt::GeorgesEditorPlugin) \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.h index fabdd600c..e21d8c57a 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_plugin.h @@ -38,7 +38,7 @@ namespace ExtensionSystem class IPluginSpec; } -namespace Plugin +namespace GeorgesQt { class GeorgesEditorForm; class GeorgesEditorPlugin : public QObject, public ExtensionSystem::IPlugin @@ -93,6 +93,6 @@ public: GeorgesEditorForm *m_georgesEditorForm; }; -} // namespace Plugin +} // namespace GeorgesQt #endif // LANDSCAPE_EDITOR_PLUGIN_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.cpp index 4e021f681..7f405fb75 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.cpp @@ -19,7 +19,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { CGeorgesFileSystemModel::CGeorgesFileSystemModel(QString ldPath, QObject *parent) @@ -159,6 +159,6 @@ void CGeorgesFileSystemModel::checkLDPath() // } // return QSortFilterProxyModel::data(index, role); //} -} /* namespace NLQT */ +} /* namespace GeorgesQt */ /* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.h index 03eb5ecc2..6c7a26055 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_filesystem_model.h @@ -20,7 +20,7 @@ #include #include -namespace Plugin +namespace GeorgesQt { class CGeorgesFileSystemModel : public QFileSystemModel @@ -74,6 +74,6 @@ private Q_SLOTS: // bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; //}; -} /* namespace NLQT */ +} /* namespace GeorgesQt */ #endif // GEORGES_FILESYSTEM_MODEL_H \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp index ac72cd747..dccb5f07b 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp @@ -27,7 +27,14 @@ #include #include #include +#include #include +#include +#include + +// OVQT Includes +#include "../core/icore.h" +#include "../core/core_constants.h" // Project includes #include "georges.h" @@ -40,7 +47,7 @@ using namespace NLMISC; using namespace NLGEORGES; -namespace Plugin +namespace GeorgesQt { CGeorgesTreeViewDialog::CGeorgesTreeViewDialog(QWidget *parent /*= 0*/) @@ -51,6 +58,11 @@ namespace Plugin m_georges = new CGeorges; loadedForm = ""; + // Set the default sheet dir dir to the level design path. + m_lastSheetDir = "."; + QSettings *settings = Core::ICore::instance()->settings(); + m_lastSheetDir = settings->value(Core::Constants::LEVELDESIGN_PATH, "l:/leveldesign").toString(); + settings->endGroup(); m_ui.setupUi(this); m_header = new ExpandableHeaderView(Qt::Horizontal, m_ui.treeView); @@ -208,9 +220,34 @@ namespace Plugin } } - void CGeorgesTreeViewDialog::addParentForm(CForm *form) + void CGeorgesTreeViewDialog::addParentForm(QString parentFormNm) { - //((CForm*)_form)->insertParent(((CForm*)_form)->getParentCount(), form->getFilename().c_str(), form); + // Try to load the form + NLGEORGES::UForm *uParentForm = m_georges->loadForm(parentFormNm.toStdString()); + NLGEORGES::CForm *parentForm = dynamic_cast(uParentForm); + NLGEORGES::CForm *mainForm = static_cast(m_form); + + CGeorgesFormProxyModel * proxyModel = dynamic_cast(m_ui.treeView->model()); + CGeorgesFormModel *model = dynamic_cast(proxyModel->sourceModel()); + + if(parentForm) + { + if (mainForm != parentForm) + { + // Check it is the same dfn + if (parentForm->Elements.FormDfn == mainForm->Elements.FormDfn) + { + // This is the parent form selector + if(!mainForm->insertParent(mainForm->getParentCount(),parentFormNm.toStdString().c_str(), parentForm)) + nlwarning("Failed to add parent form: %s", parentFormNm.toStdString().c_str()); + else + { + nlinfo("Successfullyadded parent form: %s", parentFormNm.toStdString().c_str()); + model->addParentForm(parentFormNm); + } + } + } + } } void CGeorgesTreeViewDialog::modifiedFile( ) @@ -393,6 +430,7 @@ namespace Plugin void CGeorgesTreeViewDialog::showContextMenu(const QPoint &pos) { QMenu contextMenu; + QMenu *structContext = NULL; QPoint globalPos = this->mapToGlobal(pos); // Fisrt we're going to see if we've right clicked on a new item and select it. @@ -410,32 +448,100 @@ namespace Plugin CFormItem *item = m->getItem(sourceIndex); - if ((item->parent() && item->parent()->data(0) == "parents") || item->data(0) == "parents") + // Right click on the "parents" item + if (item->data(0) == "parents") contextMenu.addAction("Add parent..."); + // Right click on a parent item + else if(item->parent() && item->parent()->data(0) == "parents") + { + contextMenu.addAction("Add parent..."); + contextMenu.addAction("Remove parent"); + } else if(item->getFormElm()->isArray()) contextMenu.addAction("Add array entry..."); else if(item->getFormElm()->isStruct()) - contextMenu.addAction("Add element..."); + { + QMenu *structContext = new QMenu("Add struct element...", this); + contextMenu.addMenu(structContext); + + NLGEORGES::UFormDfn *defn = item->getFormElm()->getStructDfn(); + if(defn) + { + for(uint defnNum=0; defnNum < defn->getNumEntry(); defnNum++) + { + std::string entryName; + std::string dummy; + UFormElm::TWhereIsValue *whereV = new UFormElm::TWhereIsValue; + bool result = defn->getEntryName(defnNum, entryName); + bool result2 = item->getFormElm()->getValueByName(dummy, entryName.c_str(), NLGEORGES::UFormElm::Eval, whereV); + + + if(result2 && *whereV != UFormElm::ValueForm) + { + structContext->addAction(entryName.c_str()); + } + delete whereV; + } + } + } else if(item->getFormElm()->isAtom() && item->valueFrom() == NLGEORGES::UFormElm::ValueForm) contextMenu.addAction("Revert to parent/default..."); - else if(item->getFormElm()->isAtom() && item->valueFrom() == NLGEORGES::UFormElm::ValueParentForm) - contextMenu.addAction("Override parent/default value..."); - else - contextMenu.addAction("Add element..."); QAction *selectedItem = contextMenu.exec(globalPos); if(selectedItem) { if(selectedItem->text() == "Add parent...") { - QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select parent sheets...")); + // Get the file extension of the form so we can build a dialog pattern. + QString file = m_form->getFilename().c_str(); + file = file.remove(0,file.indexOf(".")+1); + QString filePattern = "Parent Sheets (*."+file+")"; + + nlinfo("parent defn name '%s'", file.toStdString().c_str()); + QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select parent sheets..."), m_lastSheetDir, filePattern); if(!fileNames.isEmpty()) { - // add some parents. + Q_FOREACH(QString fileToParent, fileNames) + { + // Get just the filename. Georges doesn't want the path. + QFileInfo pathInfo( fileToParent ); + QString tmpFileName( pathInfo.fileName() ); + + nlinfo("requesting to add parent form '%s'", tmpFileName.toStdString().c_str()); + + // Call to add the form and load it into the Georges form. + addParentForm(tmpFileName); + + // Save the file lookup path for future dialog boxes. + m_lastSheetDir = pathInfo.absolutePath(); + } } + m_ui.treeView->expandAll(); } - } - } + else if(selectedItem->text() == "Remove parent") + { + NLGEORGES::CForm *form = static_cast(m_form); + QString parentFileName = item->data(0).toString(); + + for(uint num = 0; num < form->getParentCount(); num++) + { + QString curParentName = form->getParent(num)->getFilename().c_str(); + if(parentFileName == curParentName) + { + form->removeParent(num); + m->removeParentForm(parentFileName); + break; + } + } + + m_ui.treeView->expandAll(); + } + + } // if selected context menu item is valid. + } // if 'm' model valid. + + if(structContext) + delete structContext; } -} /* namespace NLQT */ +} /* namespace GeorgesQt */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h index 8c2db3d47..a7ff4c375 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.h @@ -40,7 +40,7 @@ namespace NLGEORGES using namespace NLGEORGES; -namespace Plugin +namespace GeorgesQt { class CGeorges; @@ -57,7 +57,7 @@ namespace Plugin void setModified(bool m) {m_modified = m;} CForm* getFormByName(const QString); - void addParentForm(CForm *form); + void addParentForm(QString parentFormNm); void write ( ); @@ -97,10 +97,13 @@ namespace Plugin QUndoStack *m_undoStack; + /// Contains a record of the last directory a sheet file dialog was opened for. + QString m_lastSheetDir; + bool m_modified; }; /* CGeorgesTreeViewDialog */ -} /* namespace NLQT */ +} /* namespace GeorgesQt */ #endif // GEORGES_TREEVIEWER_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.cpp index f6b9c441b..ca016e052 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.cpp @@ -40,16 +40,16 @@ using namespace NLGEORGES; -namespace Plugin +namespace GeorgesQt { CGeorgesFormModel::CGeorgesFormModel(UFormElm *rootElm, QMap< QString, QStringList> deps, QString comment, QStringList parents, bool *expanded, QObject *parent) : QAbstractItemModel(parent) { - QList rootData; - rootData << "Value" << "Data" << "Extra";// << "Type"; + + m_rootData << "Value" << "Data" << "Extra";// << "Type"; m_rootElm = rootElm; - m_rootItem = new CFormItem(m_rootElm, rootData); + m_rootItem = new CFormItem(m_rootElm, m_rootData); m_dependencies = deps; m_comments = comment; m_parents = parents; @@ -669,6 +669,27 @@ namespace Plugin Q_EMIT layoutAboutToBeChanged(); Q_EMIT layoutChanged(); } -} /* namespace Plugin */ + + void CGeorgesFormModel::addParentForm(QString parentForm) + { + beginResetModel(); + m_parents.push_back(parentForm); + delete m_rootItem; + m_rootItem = new CFormItem(m_rootElm, m_rootData); + setupModelData(); + endResetModel(); + } + + void CGeorgesFormModel::removeParentForm(QString parentForm) + { + beginResetModel(); + m_parents.removeOne(parentForm); + + delete m_rootItem; + m_rootItem = new CFormItem(m_rootElm, m_rootData); + setupModelData(); + endResetModel(); + } +} /* namespace GeorgesQt */ /* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.h index 0d8ce6e69..05fadc498 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_model.h @@ -29,7 +29,7 @@ namespace NLGEORGES { class UFormElm; } -namespace Plugin +namespace GeorgesQt { class CFormItem; @@ -56,6 +56,9 @@ namespace Plugin bool showDefaults() { return m_showDefaults;} void setShowParents( bool show ); void setShowDefaults( bool show ); + void addParentForm(QString parentForm); + void removeParentForm(QString parentForm); + NLGEORGES::UFormElm *getRootForm() { return m_rootElm; } private: void setupModelData(); @@ -64,6 +67,7 @@ namespace Plugin CFormItem* m_rootItem; NLGEORGES::UFormElm* m_rootElm; + QList m_rootData; QMap< QString, QStringList> m_dependencies; QString m_comments; QStringList m_parents; @@ -71,10 +75,10 @@ namespace Plugin bool m_showParents; bool m_showDefaults; - bool *m_expanded; + bool *m_expanded; };/* class CGeorgesFormModel */ -} /* namespace Plugin */ +} /* namespace GeorgesQt */ #endif // GEORGESFORM_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.cpp index ae3720a57..a99997925 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.cpp @@ -23,7 +23,7 @@ #include "georgesform_proxy_model.h" #include "georgesform_model.h" -namespace Plugin +namespace GeorgesQt { bool CGeorgesFormProxyModel::filterAcceptsRow(int sourceRow, @@ -76,6 +76,6 @@ namespace Plugin { return QSortFilterProxyModel::filterAcceptsColumn(sourceRow, sourceParent); } -} /* namespace Plugin */ +} /* namespace GeorgesQt */ /* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.h index 570913dab..73c384a99 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georgesform_proxy_model.h @@ -20,7 +20,7 @@ // Qt includes #include -namespace Plugin +namespace GeorgesQt { class CGeorgesFormProxyModel : public QSortFilterProxyModel @@ -40,6 +40,6 @@ namespace Plugin };/* class CGeorgesFormProxyModel */ -} /* namespace NLQT */ +} /* namespace GeorgesQt */ #endif // GEORGESFORM_PROXY_MODEL_H From 5c8ba72685fbf18e5fc5cc2d143765e0cdab7272 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Mon, 30 Apr 2012 09:38:27 +0200 Subject: [PATCH 16/66] Fixed: Compile error --- .../src/plugins/georges_editor/georges_treeview_dialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp index dccb5f07b..117395e64 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp @@ -434,7 +434,7 @@ namespace GeorgesQt QPoint globalPos = this->mapToGlobal(pos); // Fisrt we're going to see if we've right clicked on a new item and select it. - QModelIndex &index = this->m_ui.treeView->currentIndex(); + const QModelIndex &index = this->m_ui.treeView->currentIndex(); if(!index.isValid()) return; From 7abfe97f3e546604f7fa3bbf4010386f1565631c Mon Sep 17 00:00:00 2001 From: sfb Date: Thu, 3 May 2012 08:02:14 -0500 Subject: [PATCH 17/66] Changed: #1306 Implemented basic form saving. --- .../georges_editor/georges_editor_form.cpp | 4 +- .../georges_treeview_dialog.cpp | 46 ++++++++++--------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp index a9666c8db..5cf3eb9ce 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_editor_form.cpp @@ -63,7 +63,7 @@ namespace GeorgesQt m_undoStack = new QUndoStack(this); - Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); + Core::MenuManager *menuManager = Core::ICore::instance()->menuManager(); m_openAction = menuManager->action(Core::Constants::OPEN); m_newAction = new QAction(tr("&New..."), this); @@ -124,6 +124,8 @@ namespace GeorgesQt void GeorgesEditorForm::save() { + m_lastActiveDock->write(); + m_saveAction->setEnabled(false); } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp index 117395e64..f7386cd60 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/georges_editor/georges_treeview_dialog.cpp @@ -101,10 +101,12 @@ namespace GeorgesQt void CGeorgesTreeViewDialog::headerClicked(int section) { if (section == 0) + { if (*(m_header->expanded())) m_ui.treeView->expandAll(); else m_ui.treeView->collapseAll(); + } } void CGeorgesTreeViewDialog::setForm(const CForm *form) @@ -263,12 +265,12 @@ namespace GeorgesQt void CGeorgesTreeViewDialog::write( ) { - //COFile file; - //std::string s = CPath::lookup(loadedForm.toStdString(), false); - //if (file.open (s)) - //{ - // try - // { + NLMISC::COFile file; + std::string s = NLMISC::CPath::lookup(loadedForm.toStdString(), false); + if(file.open (s)) + { + try + { // if (loadedForm.contains(".typ")) // { // //nlassert (Type != NULL); @@ -281,7 +283,7 @@ namespace GeorgesQt // // flushValueChange (); // //} // //Type->write (xmlStream.getDocument (), theApp.Georges4CVS); - // //modify (NULL, NULL, false); + // //modify (NULL, NULL, false); // //flushValueChange (); // //UpdateAllViews (NULL); // //return TRUE; @@ -303,17 +305,17 @@ namespace GeorgesQt // } // else // { - // nlassert (_form != NULL); + nlassert (m_form != NULL); - // // Write the file + // Write the file // /*if (IsModified ()) // { // ((CForm*)(UForm*)Form)->Header.MinorVersion++; // }*/ // //((CForm*)(UForm*)Form)->write (xmlStream.getDocument (), lpszPathName, theApp.Georges4CVS); - // _form->write(file, false); - // setWindowTitle(windowTitle().remove("*")); - // _modified = false; + m_form->write(file, false); + setWindowTitle(windowTitle().remove("*")); + m_modified = false; // //if (strcmp (xmlStream.getErrorString (), "") != 0) // //{ // // char message[512]; @@ -327,16 +329,16 @@ namespace GeorgesQt // // Get the left view // //CView* pView = getLeftView (); // } - // } - // catch (Exception &e) - // { - // nlerror("Error while loading file: %s", e.what()); - // } - //} - //else - //{ //if (!file.open()) - // nlerror("Can't open the file %s for writing.", s.c_str()); - //} + } + catch (Exception &e) + { + nlerror("Error while loading file: %s", e.what()); + } + } + else + { + nlerror("Can't open the file %s for writing.", s.c_str()); + } } void CGeorgesTreeViewDialog::doubleClicked ( const QModelIndex & index ) From e2d6ab6e8f119fb526d6ed217dd196219504d594 Mon Sep 17 00:00:00 2001 From: vl Date: Fri, 4 May 2012 12:04:49 +0200 Subject: [PATCH 18/66] Added: new webig system --- code/web/api/client/auth.php | 49 +++ code/web/api/client/config.php.default | 20 + code/web/api/client/user.php | 23 ++ code/web/api/client/utils.php | 3 + code/web/api/common/auth.php | 57 +++ code/web/api/common/config.php.default | 28 ++ code/web/api/common/db_lib.php | 422 +++++++++++++++++++++ code/web/api/common/logger.php | 43 +++ code/web/api/common/render.php | 218 +++++++++++ code/web/api/common/user.php | 3 + code/web/api/common/utils.php | 182 +++++++++ code/web/api/data/css/ryzom_iphone.css | 248 ++++++++++++ code/web/api/data/css/ryzom_ui.css | 227 +++++++++++ code/web/api/data/css/skin_b.gif | Bin 0 -> 748 bytes code/web/api/data/css/skin_bl.gif | Bin 0 -> 129 bytes code/web/api/data/css/skin_blank.png | Bin 0 -> 11070 bytes code/web/api/data/css/skin_blank_inner.png | Bin 0 -> 8986 bytes code/web/api/data/css/skin_br.gif | Bin 0 -> 130 bytes code/web/api/data/css/skin_header_l.gif | Bin 0 -> 434 bytes code/web/api/data/css/skin_header_m.gif | Bin 0 -> 6290 bytes code/web/api/data/css/skin_header_r.gif | Bin 0 -> 977 bytes code/web/api/data/css/skin_l.gif | Bin 0 -> 477 bytes code/web/api/data/css/skin_r.gif | Bin 0 -> 488 bytes code/web/api/data/css/skin_t.gif | Bin 0 -> 315 bytes code/web/api/data/css/skin_tl.gif | Bin 0 -> 99 bytes code/web/api/data/css/skin_tr.gif | Bin 0 -> 127 bytes code/web/api/data/img/bg.jpg | Bin 0 -> 50750 bytes code/web/api/data/img/lang/de.png | Bin 0 -> 229 bytes code/web/api/data/img/lang/en.png | Bin 0 -> 396 bytes code/web/api/data/img/lang/fr.png | Bin 0 -> 2889 bytes code/web/api/data/img/lang/ru.png | Bin 0 -> 2886 bytes code/web/api/data/img/lang/sp.png | Bin 0 -> 62 bytes code/web/api/data/img/logo.gif | Bin 0 -> 6763 bytes code/web/api/index.php | 1 + code/web/api/player_auth.php | 44 +++ code/web/api/ryzom_api.php | 49 +++ code/web/api/server/auth.php | 111 ++++++ code/web/api/server/config.php.default | 31 ++ code/web/api/server/user.php | 111 ++++++ code/web/api/server/utils.php | 49 +++ code/web/app/app_test/favicon.png | Bin 0 -> 2596 bytes code/web/app/app_test/index.php | 34 ++ code/web/app/app_test/lang.php | 15 + code/web/app/config.php.default | 26 ++ code/web/app/index.php | 35 ++ code/web/app/lang.php | 371 ++++++++++++++++++ 46 files changed, 2400 insertions(+) create mode 100644 code/web/api/client/auth.php create mode 100644 code/web/api/client/config.php.default create mode 100644 code/web/api/client/user.php create mode 100644 code/web/api/client/utils.php create mode 100644 code/web/api/common/auth.php create mode 100644 code/web/api/common/config.php.default create mode 100644 code/web/api/common/db_lib.php create mode 100644 code/web/api/common/logger.php create mode 100644 code/web/api/common/render.php create mode 100644 code/web/api/common/user.php create mode 100644 code/web/api/common/utils.php create mode 100644 code/web/api/data/css/ryzom_iphone.css create mode 100644 code/web/api/data/css/ryzom_ui.css create mode 100644 code/web/api/data/css/skin_b.gif create mode 100644 code/web/api/data/css/skin_bl.gif create mode 100644 code/web/api/data/css/skin_blank.png create mode 100644 code/web/api/data/css/skin_blank_inner.png create mode 100644 code/web/api/data/css/skin_br.gif create mode 100644 code/web/api/data/css/skin_header_l.gif create mode 100644 code/web/api/data/css/skin_header_m.gif create mode 100644 code/web/api/data/css/skin_header_r.gif create mode 100644 code/web/api/data/css/skin_l.gif create mode 100644 code/web/api/data/css/skin_r.gif create mode 100644 code/web/api/data/css/skin_t.gif create mode 100644 code/web/api/data/css/skin_tl.gif create mode 100644 code/web/api/data/css/skin_tr.gif create mode 100644 code/web/api/data/img/bg.jpg create mode 100644 code/web/api/data/img/lang/de.png create mode 100644 code/web/api/data/img/lang/en.png create mode 100644 code/web/api/data/img/lang/fr.png create mode 100644 code/web/api/data/img/lang/ru.png create mode 100644 code/web/api/data/img/lang/sp.png create mode 100644 code/web/api/data/img/logo.gif create mode 100644 code/web/api/index.php create mode 100644 code/web/api/player_auth.php create mode 100644 code/web/api/ryzom_api.php create mode 100644 code/web/api/server/auth.php create mode 100644 code/web/api/server/config.php.default create mode 100644 code/web/api/server/user.php create mode 100644 code/web/api/server/utils.php create mode 100644 code/web/app/app_test/favicon.png create mode 100644 code/web/app/app_test/index.php create mode 100644 code/web/app/app_test/lang.php create mode 100644 code/web/app/config.php.default create mode 100644 code/web/app/index.php create mode 100644 code/web/app/lang.php diff --git a/code/web/api/client/auth.php b/code/web/api/client/auth.php new file mode 100644 index 000000000..cab8a5886 --- /dev/null +++ b/code/web/api/client/auth.php @@ -0,0 +1,49 @@ +. + */ + +require_once(RYAPI_PATH.'client/config.php'); + +// Og (non-ryzom.com) method +function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&authserver='.$authserver; + + $res = file_get_contents($fn); + return $res == '1'; +} + +// Ig method +function ryzom_authenticate_ingame($cid, $name, $authkey) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&ig=1'; + + $res = file_get_contents($fn); + echo $res; + return $res == '1'; +} + +// Session method +function ryzom_authenticate_with_session($name, $redirect) { + global $_RYZOM_API_CONFIG; + $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name; + + $res = file_get_contents($fn); + return $res == '1'; +} + +?> diff --git a/code/web/api/client/config.php.default b/code/web/api/client/config.php.default new file mode 100644 index 000000000..3c8ca869d --- /dev/null +++ b/code/web/api/client/config.php.default @@ -0,0 +1,20 @@ +. + */ + +// Url where player_auth.php is located +define('RYAPI_AUTH_SCRIPT', ''); diff --git a/code/web/api/client/user.php b/code/web/api/client/user.php new file mode 100644 index 000000000..de526dcca --- /dev/null +++ b/code/web/api/client/user.php @@ -0,0 +1,23 @@ +. + */ + +function ryzom_user_get_info($cid) { + return Array(); +} + +?> diff --git a/code/web/api/client/utils.php b/code/web/api/client/utils.php new file mode 100644 index 000000000..62a2de0c8 --- /dev/null +++ b/code/web/api/client/utils.php @@ -0,0 +1,3 @@ + diff --git a/code/web/api/common/auth.php b/code/web/api/common/auth.php new file mode 100644 index 000000000..b6bcdd799 --- /dev/null +++ b/code/web/api/common/auth.php @@ -0,0 +1,57 @@ +The application '._t(APP_NAME).' require authentication. Please enter your credentials'; + + $c .= '
'.$welcome_message.'

'; + + if ($user['message']) + $c .= '
'._t($user['message']).'

'; + $c .= ryzom_render_login_form($name, false); + echo ryzom_app_render(_t('app_'.APP_NAME), $c); + exit; + } + return false; + } + } + + if ($lang) + $_SESSION['lang'] = $lang; + + // get user informations + $user = ryzom_user_get_info($cid); + $user['lang'] = $_SESSION['lang']; + + $user['id'] = ryzom_get_user_id($cid, $user['char_name'], $user['creation_date']); + unset($user['last_played_date']); + unset($user['creation_date']); + return true; +} + +?> diff --git a/code/web/api/common/config.php.default b/code/web/api/common/config.php.default new file mode 100644 index 000000000..3a00bb04e --- /dev/null +++ b/code/web/api/common/config.php.default @@ -0,0 +1,28 @@ +. + */ + +// Url where the api is +define('RYAPI_URL', 'http://'); +if (!defined('RYAPI_PATH')) + define('RYAPI_PATH', dirname(__FILE__).'/'); +// used by "home" link +if (!defined('RYAPP_URL')) + define('RYAPP_URL', 'http://'); + +?> diff --git a/code/web/api/common/db_lib.php b/code/web/api/common/db_lib.php new file mode 100644 index 000000000..c3c7e8677 --- /dev/null +++ b/code/web/api/common/db_lib.php @@ -0,0 +1,422 @@ +. + */ + +define('SQL_DEF_TEXT', 0); +define('SQL_DEF_BOOLEAN', 1); +define('SQL_DEF_INT', 2); +define('SQL_DEF_DATE', 3); + + +// Wrapper for SQL database interactions +class ServerDatabase +{ + var $hostname = ''; + var $username = ''; + var $password = ''; + var $database = ''; + + var $_connection = Null; + + function ServerDatabase($host='', $user='', $passwd='', $dbname='') + { + if (($host != '') && ($user != '') && ($dbname != '')) + { + $this->hostname = $host; + $this->username = $user; + $this->password = $passwd; + $this->database = $dbname; + } + + if (($this->hostname != '') && ($this->username != '') && ($this->database != '')) + { + $this->_connection = mysql_connect($this->hostname, $this->username, $this->password) + or die("ERR1"); // ace . $this->get_error()); + $this->select_db($this->database); + } + } + + function close() + { + @mysql_close($this->_connection); + } + + function query($sql_statement) + { + $result = mysql_query($sql_statement, $this->_connection); + return $result; + } + + function select_db($dbname) { + $this->database = $dbname; + mysql_select_db($this->database, $this->_connection) or die("Database selection error : " . $this->get_error()); + } + + function num_rows($result) + { + return @mysql_num_rows($result); + } + + function fetch_row($result, $result_type=MYSQL_BOTH) + { + return @mysql_fetch_array($result, $result_type); + } + + function fetch_assoc($result) + { + return @mysql_fetch_array($result, MYSQL_ASSOC); + } + + + function query_single_row($sql_statement) + { + $result = $this->query($sql_statement); + return @mysql_fetch_array($result); + } + + function free_result($result) + { + @mysql_free_result($result); + } + + function get_error() + { + return mysql_errno($this->_connection) .": ". mysql_error($this->_connection); + } + + function last_insert_id() + { + return @mysql_insert_id(); + } + + function change_to($host,$user,$pass,$dbname) + { + $this->close(); + $this->hostname = $host; + $this->username = $user; + $this->password = $pass; + $this->database = $dbname; + $this->ServerDatabase(); + } +} + + + + +class ryDB { + + private static $_instances = array(); + private $db; + private $defs = array(); + private $errors = ''; + + + private function __construct($db_name) { + global $_RYZOM_API_CONFIG; + + $this->db = new ServerDatabase(RYAPI_WEBDB_HOST, RYAPI_WEBDB_LOGIN, RYAPI_WEBDB_PASS, $db_name); + $this->db->query("SET NAMES utf8"); + } + + public static function getInstance($db_name) { + if (!array_key_exists($db_name, self::$_instances)) + self::$_instances[$db_name] = new ryDB($db_name); + + self::$_instances[$db_name]->db->select_db($db_name); + return self::$_instances[$db_name]; + } + + function setDbDefs($table, $defs) { + $this->defs[$table] = $defs; + } + + function getDefs($table) { + if (!array_key_exists($table, $this->defs)) + die("Please add tables defs using setDbDefs('$table', \$defs)"); + return $this->defs[$table]; + } + + function getErrors() { + return $this->db->get_error(); + } + + function now() { + return date('Y-m-d H:i:s', time()); + } + + function toDate($timestamp) { + return date('Y-m-d H:i:s', $timestamp); + } + + function fromDate($string_date) { + return strtotime($string_date); + } + + function addDbTableProp($table, $props) { + $this->props[$table] = $props; + } + + /// DIRECT QUERY + function sqlQuery($sql) { + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result)) { + $ret[] = $row; + } + return $ret; + } + + + /// QUERY /// + function sqlSelect($table, $props, $values=array(), $extra='') { + if ($table) { + $sql = "SELECT\n\t"; + $params = array(); + $test = array(); + if (!$props) + die("Bad Select on [$table] : missing props"); + + foreach($props as $name => $type) + $params[] = '`'.addslashes($name).'`'; + + foreach($values as $name => $value) { + if ($name[0] == '=') + $test[] = '('.addslashes(substr($name, 1)).' LIKE '.var_export($value, true).')'; + else + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + } + $sql .= implode(",\n\t", $params)."\nFROM\n\t".$table."\n"; + if ($test) + $sql .= "WHERE\n\t".implode("\nAND\n\t", $test); + } + + if ($extra) + $sql .= "\n".$extra; + return $sql.';'; + + } + + function querySingle($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + return $this->db->fetch_row($result); + } + + function querySingleAssoc($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + return $this->db->fetch_row($result, MYSQL_ASSOC); + } + + function query($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result)) { + $ret[] = $row; + } + return $ret; + } + + function queryAssoc($table, $values=array(), $extra='') { + $sql = $this->sqlSelect($table, $this->getDefs($table), $values, $extra); + $result = $this->db->query($sql); + $ret = array(); + while ($row = $this->db->fetch_row($result, MYSQL_ASSOC)) { + $ret[] = $row; + } + return $ret; + } + + /// INSERT /// + function sqlInsert($table, $props, $vals) { + $sql = 'INSERT INTO '.$table.' '; + $params = array(); + $values = array(); + foreach($props as $name => $type) { + if (!isset($vals[$name])) + continue; + $params[] = $name; + switch ($type) { + case SQL_DEF_BOOLEAN: + $values[] = $vals[$name]?1:0; + break; + case SQL_DEF_INT: + $values[] = $vals[$name]; + break; + case SQL_DEF_DATE: // date + if (is_string($vals[$name])) + $values[] = "'".addslashes($vals[$name])."'"; + else + $values[] = "'".$this->toDate($vals[$name])."'"; + break; + default: + $values[] = "'".addslashes($vals[$name])."'"; + break; + } + } + $sql .= "(\n\t".implode(",\n\t", $params)."\n) VALUES (\n\t".implode(",\n\t", $values)."\n);"; + return $sql; + } + + function insert($table, $values) { + $sql = $this->sqlInsert($table, $this->getDefs($table), $values); + $this->db->query($sql); + return $this->db->last_insert_id(); + } + + /// DELETE /// + function sqlDelete($table, $values=array(), $where='') { + $sql = "DELETE FROM\n\t".$table."\n"; + $test = array(); + foreach($values as $name => $value) + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + + if ($test or $where) + $sql .= "WHERE\n\t"; + if ($test) + $sql .= implode("\nAND\n\t", $test); + if ($where) + $sql .= "\n".$where; + return $sql.';'; + } + + function delete($table, $values=array(), $where='') { + $sql = $this->sqlDelete($table, $values, $where); + $result = $this->db->query($sql); + return $result; + } + + /// UPDATE /// + function sqlUpdate($table, $props, $vals, $tests, $extra) { + $sql = 'UPDATE '.$table.' SET '; + $params = array(); + $test = array(); + $values = array(); + foreach($props as $name => $type) { + if (!array_key_exists($name, $vals)) + continue; + switch ($type) { + case SQL_DEF_BOOLEAN: + $values[] = '`'.$name.'` = '.($vals[$name]?'1':'0'); + break; + case SQL_DEF_DATE: + if (is_string($vals[$name])) + $values[] = '`'.$name.'` = \''.addslashes($vals[$name]).'\''; + else + $values[] = '`'.$name.'` = \''.$this->toDate($vals[$name]).'\''; + break; + default: + $values[] = '`'.$name.'` = \''.addslashes($vals[$name]).'\''; + break; + } + } + $sql .= "\n\t".implode(",\n\t", $values)."\n"; + + foreach($tests as $name => $value) { + $test[] = '('.addslashes($name).' = '.var_export($value, true).')'; + } + if ($test) + $sql .= "WHERE\n\t".implode("\nAND\n\t", $test); + + $sql .= "\n".$extra; + + return $sql; + } + + + function update($table, $values=array(), $test=array(), $extra='') { + $sql = $this->sqlUpdate($table, $this->getDefs($table), $values, $test, $extra); + $result = $this->db->query($sql); + return $result; + } + + function sqlInsertOrUpdate($table, $props, $vals) { + $sql = $this->sqlInsert($table, $props, $vals); + $sql = substr($sql, 0, strlen($sql)-1); + $params = array(); + $test = array(); + $values = array(); + foreach($props as $prop) { + if (!array_key_exists($prop[2], $vals)) + continue; + $type = $prop[0]; + $check = $prop[1]; + $name = $prop[2]; + if ($type{0} == '#') + $type = substr($type, 1); + if (($type{0} == '>') or ($type == 'id')) + continue; + switch ($type) { + case 'trad': + $values[] = '`'.$name."` = '".addslashes($vals[$name])."'"; + break; + case 'textarea': + case 'string': + case 'option': + $values[] = '`'.$name."` = '".addslashes($vals[$name])."'"; + break; + case 'id': + case 'int': + case 'float': + $values[] = '`'.$name.'` = '.addslashes($vals[$name]); + break; + case 'bool': + $values[] = '`'.$name.'` = '.($vals[$name]?'1':'0'); + break; + } + } + $sql .= "\nON DUPLICATE KEY UPDATE\n\t".implode(",\n\t", $values)."\n"; + return $sql; + } + + function insertOrUpdate($table, $values) { + $sql = $this->sqlInsertOrUpdate($table, $this->getDefs($table), $values); + return $result; + } + + + /// Display + function getTableHtml($name, $params, $values, $order_by='') + { + $ret = ''; + $tr_header = ''; + $ret .= _s('t header', $tr_header); + $i = 0; + if (!$values) + return ''; + $current_section = ''; + foreach ($values as $rows) { + if ($order_by && $rows[$order_by] != $current_section) { + $current_section = $rows[$order_by]; + if ($current_section != '0') + $ret .= _s('t row ', ''.str_repeat('', count($params)-1)); + } + $td = ''; + foreach ($params as $test => $param) + $td .= ''; + $ret .= _s('t row '.strval($i % 2), $td); + $i++; + } + $ret .= '
 '; + $tr_header .= implode(' ', array_keys($params)).''._s('section', $current_section).''._s('section', ' ').' '.$rows[$param].'
'; + return $ret; + } + +} + +?> diff --git a/code/web/api/common/logger.php b/code/web/api/common/logger.php new file mode 100644 index 000000000..f4909e721 --- /dev/null +++ b/code/web/api/common/logger.php @@ -0,0 +1,43 @@ +log_indent += $indent; + if ($log) { + $tabs = str_repeat(" ", $this->log_indent); + $a = $tabs.str_replace("\n", "\n ".$tabs, $log); + $this->logs[] = ''.$a.''; + } + } + + function addPrint($log, $color='#FFFF00') { + $this->logs[] = ''.$log.''; + } + + function addError($log) { + $this->logs[] = ' ERROR: '.$log.''; + } + + function getLogs() { + $ret = ''; + if ($this->logs && $this->enable) + $ret = "Debug\n".implode("\n", $this->logs); + $this->logs = array(); + return $ret; + } +} + + +?> diff --git a/code/web/api/common/render.php b/code/web/api/common/render.php new file mode 100644 index 000000000..a2ec31795 --- /dev/null +++ b/code/web/api/common/render.php @@ -0,0 +1,218 @@ +. + */ + +function ryzom_app_render($title, $content, $bgcolor='', $javascript=array(), $homeLink=false) { + $c = ''; + // Render header + $title_prefix = ''; + if (ON_IPHONE) { + $title_prefix = 'Ryzom - '; + } + + if (!$bgcolor) + $bgcolor = '#000000'.(RYZOM_IG?'00':''); + + $c .= ''."\n"; + $c .= ' + '."\n"; + $c .= ' '.$title_prefix.(translation_exists($title)?_t($title):$title).''."\n"; + $c .= ' '."\n"; + + if (!RYZOM_IG) { + $c .= ryzom_render_header(); + $c .= ryzom_render_header_www(); + } + + $events = ON_IPHONE ? 'onorientationchange="updateOrientation();" ' : ''; + + $c .= ' '."\n"; + + $c .= ' '."\n"; + + // Javascript + $js_code = ''; + foreach ($javascript as $js) + $js_code .= ''; + $c .= $js_code; + + if (RYZOM_IG) + $c .= $content; + else{ + $c .= ryzom_render_www(ryzom_render_window($title, $content, $homeLink)); + } + + $c .= ''; + return $c; +} + +function ryzom_render_header() { + if (ON_IPHONE) { + return ''; + } else { + return ' '; + } +} + +// Call this inside the part if you want to use ryzom_render_www +function ryzom_render_header_www() { + if (ON_IPHONE) { + return ' + + + + + '; + } else { + return ' + +'; + } +} + +// Render a Ryzom style window +function ryzom_render_window($title, $content, $homeLink=false) { + return ryzom_render_window_begin($title, $homeLink) . $content . ryzom_render_window_end(); +} + +function ryzom_render_window_begin($title, $homeLink=false) { + + if ($homeLink === false) + $homeLink = ''._t('home').''; + + return ' +
+
+
'.$title_prefix.(translation_exists($title)?_t($title):$title).$homeLink.'
+
+
+
+
+'; +} + +function ryzom_render_window_end() { + return '
+
'.ryLogger::getInstance()->getLogs().'
+

powered by ryzom-api

+
+ '; +} + +// Render a webpage using www.ryzom.com style +function ryzom_render_www($content) { + return ryzom_render_www_begin() . $content . ryzom_render_www_end(); +} + +function ryzom_render_www_begin($url='') { + $style1 = 'position: relative; padding-top: 20px; padding-right: 30px; margin-bottom: -3px'; + $style2 = 'position: absolute; bottom: 0; right: 0; '; + if (ON_IPHONE) { + $style1 = 'position: relative; padding-top: 30px; padding-right: 30px; '; + $style2 = 'position: fixed; top: 0; right: 0; padding-right: 0px;'; + $marginBottom = ''; + } + if (!$url) { + $url_params = parse_query($_SERVER['REQUEST_URI']); + unset($url_params['lang']); + + $url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.http_build_query($url_params); + } + return ' +
+
+
+ English + French + German + Russian +
+ +
+
+'; +} + +function ryzom_render_www_end() { + return '
'; +} + +function ryzom_render_login_form($char, $aligned=true) { + $c = ''; + if ($aligned) { + $c .= '
'; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + } else { + $c .= '
'._t('enter_char').'
'._t('enter_password').'
'; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + $c .= ''; + } + $c .= '
'._t('login').'
'._t('password').'
'; + return $c; +} + +?> diff --git a/code/web/api/common/user.php b/code/web/api/common/user.php new file mode 100644 index 000000000..62a2de0c8 --- /dev/null +++ b/code/web/api/common/user.php @@ -0,0 +1,3 @@ + diff --git a/code/web/api/common/utils.php b/code/web/api/common/utils.php new file mode 100644 index 000000000..9f12fdfc1 --- /dev/null +++ b/code/web/api/common/utils.php @@ -0,0 +1,182 @@ + $v) { + if (is_int($k) && $prefix != null) { + $k = urlencode($prefix . $k); + } + if ((!empty($key)) || ($key === 0)) $k = $key.'['.urlencode($k).']'; + if (is_array($v) || is_object($v)) { + array_push($ret, http_build_query($v, '', $sep, $k)); + } else { + array_push($ret, $k.'='.urlencode($v)); + } + } + if (empty($sep)) $sep = ini_get('arg_separator.output'); + return implode($sep, $ret); + } +} + + +/*** + * + * Translation utilities + * + * ***/ + +function translation_exists($id) { + global $user, $ryzom_texts; + return isset($ryzom_texts[$id]) && isset($ryzom_texts[$id][$user['lang']]); +} + +// Translate the $id in the selected language +function get_translation($id, $lang, $args=array()) { + global $ryzom_texts, $user; + if(!isset($ryzom_texts[$id])) return '{'.$id.'}'; + if(!isset($ryzom_texts[$id][$lang])) return '{'.$id.'['.$lang.']}'; + if($ryzom_texts[$id][$lang] == '' && isset($ryzom_texts[$id]['en'])) return @vsprintf($ryzom_texts[$id]['en'], $args); + return @vsprintf($ryzom_texts[$id][$lang], $args); +} + + +// Translate the $id in the user language +function _t($id, $args=array()) { + global $ryzom_texts, $user; + + $a = ''; + if ($args) { + if (is_array($args)) { + $a = array(); + foreach ($args as $arg) + $a[] = strval($arg); + $a = ' '.implode(', ', $a); + } else + $a = ' '.strval($args); + } + if(!isset($ryzom_texts[$id])) return '{'.$id.$a.'}'; + if(!isset($ryzom_texts[$id][$user['lang']])) return '{'.$id.'['.$user['lang'].']'.$a.'}'; + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['en']) && $ryzom_texts[$id]['en'] != '') return @vsprintf($ryzom_texts[$id]['en'], $args); + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['fr']) && $ryzom_texts[$id]['fr'] != '') return '{'.$id.$a.'}'; + if($ryzom_texts[$id][$user['lang']] == '' && isset($ryzom_texts[$id]['de']) && $ryzom_texts[$id]['de'] != '') return '{'.$id.$a.'}'; + return @vsprintf($ryzom_texts[$id][$user['lang']], $args); +} + +/*** + * + * Ryzom time + * + * ***/ + + + +// Get a human and translated readable time, for example "3 days ago" +function ryzom_relative_time($timestamp) { + global $ryzom_periods, $user; + $difference = time() - $timestamp; + $lengths = array("60","60","24","7","4.35","12","10"); + + if ($difference >= 0) { // this was in the past + $ending = _t('ago'); + } else { // this was in the future + $difference = -$difference; + $ending = _t('to_go'); + } + for($j = 0,$m=count($lengths); $j<$m && $difference >= $lengths[$j]; $j++) + $difference /= $lengths[$j]; + // round hours as '1.2 hours to go' + $difference = round($difference, ($j == 2) ? 1 : 0); + + $form = ($difference == 1) ? 'singular' : 'plural'; + + // Handle exceptions + // French uses singular form if difference = 0 + if ($user['lang'] == 'fr' && ($difference == 0)) { + $form = 'singular'; + } + // Russian has a different plural form for plurals of 2 through 4 + if ($user['lang'] == 'ru' && ($form == 'plural')) { + if ($difference < 5) { + $form = '2-4'; + } + } + + $final = $ryzom_periods[$user['lang']][$form][$j]; + $text = _t('date_format', array($difference, $final, $ending)); + return $text; +} + +// Get a human and translated absolute date +function ryzom_absolute_time($timestamp) { + global $user, $ryzom_daysofweek, $ryzom_monthnames; + $day_of_month = date("j", $timestamp); + $dow = date("w", $timestamp); + $month = date("n", $timestamp); + $day_of_week = $ryzom_daysofweek[$user['lang']][$dow]; + $month_str = $ryzom_monthnames[$user['lang']][$month-1]; + $text = _t("absolute_date_format", array($day_of_month, $day_of_week, $month_str, $month, date("m", $timestamp), date("d", $timestamp))); + return $text; +} + +/*** + * + * Debug tools + * + * ***/ + +function p($var, $value=NULL) { + ob_start(); + debug_print_backtrace(); + $bt = ob_get_contents(); + ob_end_clean(); + $bt = explode("\n",$bt); + $bt = explode('[', $bt[1]); + ob_start(); + echo ''.substr($bt[count($bt)-1], 0, -1)."\n"; + if ($value !== NULL) { + echo ''.$var.' : '; + $var = $value; + } + //if (is_array($var)) + echo '
';
+	print_r($var);
+	echo '
'; +// else + // var_dump($var); + ryLogger::getInstance()->addPrint(ob_get_contents()); + ob_end_clean(); +} + +?> diff --git a/code/web/api/data/css/ryzom_iphone.css b/code/web/api/data/css/ryzom_iphone.css new file mode 100644 index 000000000..c837ffbf4 --- /dev/null +++ b/code/web/api/data/css/ryzom_iphone.css @@ -0,0 +1,248 @@ +/* Copyright (C) 2009 Winch Gate Property Limited + * + * This file is part of ryzom_api. + * ryzom_api is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ryzom_api is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ryzom_api. If not, see . + */ + +html, body, form, fieldset, p, div, h1, h2, h3, h4, h5, h6 { + margin:0; + padding:0; + -webkit-text-size-adjust: none; +} + +body { + font-size: 14px; + background: black; + font-family: Helvetica; +} + +ul li { + padding: 0px 4px 10px 2px; + list-style: circle outside; +} +ol li { + padding: 0px 4px 10px 2px; +} +.ryzom-ui p { + padding-bottom:8px; +} + +#main { + clear: both; + padding-top: 0px; + overflow:auto; + margin-left:auto; + margin-right:auto; + text-align:left +} +.error { + padding:.5em; + background:#ff5555; + color:white; + font-weight:bold +} +/*----------------------------- + ORIENTATION +-----------------------------*/ + +.content_wide, +.content_normal { + display:none; +} + +.show_normal { + width: 320px; +} + +.show_wide { + width: 480px; +} + +.show_wide .content_wide, +.show_normal .content_normal { + display: block; +} + +/* ---------------------- */ + + +.ryzom-ui { + color: white; +} +.ryzom-ui input, .ryzom-ui select { + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; + background-color: #37402b; + color: #ddd; + font-size: 16px; + margin: 2px 0 5px 0; +} +.ryzom-ui input[type=text] { + width: 96%; +} + +.ryzom-ui textarea { + width: 96%; + background-color: black; + color: white; + font-size: 16px; + font-family: Helvetica; +} +/* input[type=submit] will make IE6 to ignore whole CSS rule, so cant combine this with .ryzom-ui-button below */ +input[type=submit] { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +input.ryzom-ui-button, .ryzom-ui-button { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} + +a, a:visited {color:orange} + +a:hover {color:orange} + +a.ryzom-ui-button, a.ryzom-ui-button:visited { + color: white; + padding: 0 .5em; + text-decoration: none; +} +a.ryzom-ui-button:hover { + background: #536130; + color: #ddd; +} +/* window without title - just borders */ +.ryzom-ui-tl { +} +.ryzom-ui-tr { +} +.ryzom-ui-t { + background-image: url(skin_t.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0; +} +/* window with proper header */ +.ryzom-ui-header .ryzom-ui-tl { + margin: 0px 0px; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-tr { + height: 32px; +} +.ryzom-ui-header .ryzom-ui-t { + background-image: url(skin_header_m.gif); + background-repeat: repeat-x; + background-position: left top; + padding: 7px 0 0 12px; + height: 32px; + text-transform: uppercase; + color: white; + border-top: 1px solid #030403; +} +/* window body */ +.ryzom-ui-l { +} +.ryzom-ui-r { +} +.ryzom-ui-m { + margin: 0 0px; + padding: 0px; + background-image: url(skin_blank.png); + background-repeat: repeat; +} +.ryzom-ui-body { + background-image: url(skin_blank_inner.png); + background-repeat: repeat; + /* leave 5px room after bottom border */ + margin: 0 8px 5px 2px; + padding: 5px 5px 5px 5px; + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; +} +/* window bottom border */ +.ryzom-ui-bl { + height: 8px; +} +.ryzom-ui-br { + height: 8px; +} +.ryzom-ui-b { + height: 8px; + margin: 0 8px; +} +.ryzom-ui-notice { + margin: 0px; + padding: 0px; + color: #999; + text-align: center; +} +a.ryzom-ui-notice, a.ryzom-ui-notice:visited { + margin: 0px; + padding: 0px; + color: #BBB; + padding: 0 .5em; + text-decoration: underline; +} +a.ryzom-ui-notice:hover { + color: gray; +} + +.ryzom-ui-t .ryzom-ui-text-button { + font-size: 85%; +} +a.ryzom-ui-text-button, a:visited.ryzom-ui-text-button { + color:#FFFF11; + text-decoration:none; +} + +.ryzom-ui-text-button { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} +.ryzom-ui-text-button { + padding: 0;margin: 0; + border-color: #ff8 #ff3 #ff3 #ff8; + border-width: 1px; + border-style: solid; + padding: 0px 4px; + color: white; +} + +.ryzom-ui-wrap-ul { + float: left; + text-align: center; + padding: 0; + list-style: none; +} + +.ryzom-ui-wrap-li { + float: left; + margin: 0 0 10px 5px; + width: 6.1em; + list-style: none; + height: 70px; +} diff --git a/code/web/api/data/css/ryzom_ui.css b/code/web/api/data/css/ryzom_ui.css new file mode 100644 index 000000000..8342b77f8 --- /dev/null +++ b/code/web/api/data/css/ryzom_ui.css @@ -0,0 +1,227 @@ +/* Copyright (C) 2009 Winch Gate Property Limited + * + * This file is part of ryzom_api. + * ryzom_api is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ryzom_api is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ryzom_api. If not, see . + */ + +/* + * Check ryzom_api/functions_render.php for easy php function to render ryzom layout or use this following html: + * +
+
+
+
+
+
+
+
+
+ */ + +.ryzom-ui { + color: white; +} +.ryzom-ui input, .ryzom-ui select { + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; + background-color: #37402b; + color: #ddd; + font-size: 12px; + margin: 2px 0 5px 0; +} +.ryzom-ui input[type=text] { + width: 100%; +} + +.ryzom-ui textarea { + width: 98%; +} + +/* input[type=submit] will make IE6 to ignore whole CSS rule, so cant combine this with .ryzom-ui-button below */ +input[type=submit] { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +input.ryzom-ui-button, .ryzom-ui-button { + border-bottom: 1px solid #030403; + border-left: 1px solid #6e7f57; + border-top: 1px solid #889e6c; + border-right: 1px solid #272d1f; + background-color: #435120; +} +a.ryzom-ui-button, a.ryzom-ui-button:visited { + color: white; + padding: 0 .5em; + text-decoration: none; +} +a.ryzom-ui-button:hover { + background: #536130; + color: #ddd; +} +/* window without title - just borders */ +.ryzom-ui-tl { + background-image: url(skin_tl.gif); + background-repeat: no-repeat; + background-position: left top; + width: 100%; height: 8px; +} +.ryzom-ui-tr { + background-image: url(skin_tr.gif); + background-repeat: no-repeat; + background-position: right top; + height: 8px; +} +.ryzom-ui-t { + background-image: url(skin_t.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0 8px; +} +/* window with proper header */ +.ryzom-ui-header .ryzom-ui-tl { + margin: 0px 0px; + background-image: url(skin_header_l.gif); + background-repeat: no-repeat; + background-position: left top; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-tr { + background-image: url(skin_header_r.gif); + background-repeat: no-repeat; + background-position: right top; + height: 32px; +} +.ryzom-ui-header .ryzom-ui-t { + background-image: url(skin_header_m.gif); + background-repeat: repeat-x; + background-position: left top; + margin-left: 12px; + margin-right: 26px; + padding-top: 9px; + height: 32px; + text-transform: uppercase; + color: white; +} +/* window body */ +.ryzom-ui-l { + background-image: url(skin_l.gif); + background-position: left top; + background-repeat: repeat-y; + width: 100%; +} +.ryzom-ui-r { + background-image: url(skin_r.gif); + background-position: right top; + background-repeat: repeat-y; + width: 100%; +} +.ryzom-ui-m { + margin: 0 8px; + padding: 8px; + background-image: url(skin_blank.png); + background-repeat: repeat; +} +.ryzom-ui-body { + background-image: url(skin_blank_inner.png); + background-repeat: repeat; + /* leave 5px room after bottom border */ + margin: 0px 0 5px 0; + padding: 10px 10px 5px 10px; + border-top: 1px solid #030403; + border-right: 1px solid #6e7f57; + border-bottom: 1px solid #889e6c; + border-left: 1px solid #272d1f; +} +/* window bottom border */ +.ryzom-ui-bl { + background-image: url(skin_bl.gif); + background-repeat: no-repeat; + background-position: left top; + height: 8px; +} +.ryzom-ui-br { + background-image: url(skin_br.gif); + background-repeat: no-repeat; + background-position: right top; + height: 8px; +} +.ryzom-ui-b { + background-image: url(skin_b.gif); + background-repeat: repeat-x; + background-position: left top; + height: 8px; + margin: 0 8px; +} +.ryzom-ui-notice { + margin: 0px; + padding: 0px; + color: #333; + text-align: center; +} +a.ryzom-ui-notice, a.ryzom-ui-notice:visited { + margin: 0px; + padding: 0px; + color: #555; + padding: 0 .5em; + text-decoration: underline; +} +a.ryzom-ui-notice:hover { + color: gray; +} + +.ryzom-ui-t .ryzom-ui-text-button { + font-size: 85%; +} +a.ryzom-ui-text-button, a:visited.ryzom-ui-text-button { + color:#FFFF11; + text-decoration:none; +} + +.ryzom-ui-text-button { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} +.ryzom-ui-text-button { + padding: 0;margin: 0; + border-color: #ff8 #ff3 #ff3 #ff8; + border-width: 1px; + border-style: solid; + padding: 0px 4px; + color: white; +} + +.ryzom-ui-wrap-ul { + float: left; + text-align: center; + padding: 0; + list-style: none; + margin-top: -5px; + margin-bottom: -20px; +} + +.ryzom-ui-wrap-li { + float: left; + margin: 0 5px 10px 5px; + width: 6.1em; + padding: 0; + list-style: none; + height: 70px; +} diff --git a/code/web/api/data/css/skin_b.gif b/code/web/api/data/css/skin_b.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1a0390bca7bfd19ebec43da73eba1772bafaa62 GIT binary patch literal 748 zcmZ?wbhEHbY+&GEIOfR!1cHKsLP9_U1j52#EDQu9Km-IJLKKKZfk;$L42ZN=iy9D=Vw2s%mR%>+0$n8ynl( z+dDcs)~sIre<%ROe}c|Msfi`2DGKG8B^e6tp1uJLia%KxxftphbU@JqiYNy5e+@=W z%`L5M?H!$6-95d1{T&RGCQq3R(eXZ zVv_O-iZZftqLPa8G7>VPB4RRf;u=P3(jp3SDk|z*blhFt937l=owY^9U98RRZEf6~ zEggh~rG!L<4l4s=SKdfROW)Mk#KKP7XTpgKj!mundI>iwrYAbJ@CusTIA!pdm5oQ( zz~R9J%>zx$%zPbxDiRJdv8uCb6dZVPu#tsNM#dl^;b3#WnzNNbrqGf`Mm`Rch6fIf zC)jw?)O2TFX*|uyJ*iD4^HRe_RzqeUi3JNBPORh>=y|iU)X`&tJa>(ZzyakG%%&cX zPR;e+zV7bsiqEg^p5DIx{_X`#+;ToU3Le;Z2y4fk*|G8Q@d?V_^L%!0dU|?>arV74 JmW2uo)&N9#QHKBk literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_bl.gif b/code/web/api/data/css/skin_bl.gif new file mode 100644 index 0000000000000000000000000000000000000000..459dc00654dbdbfabe3f6ab1032995e26b485ad9 GIT binary patch literal 129 zcmZ?wbhEHbA5G*1U)9LQh>7D)lc0tZHipahS3Qw4Z#1ttn*$h~Z-&6ROy Gum%9i_b>JU literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_blank.png b/code/web/api/data/css/skin_blank.png new file mode 100644 index 0000000000000000000000000000000000000000..0fefeaab0dcd339231a9c5c12729382873e9ebe6 GIT binary patch literal 11070 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_blank_inner.png b/code/web/api/data/css/skin_blank_inner.png new file mode 100644 index 0000000000000000000000000000000000000000..b728324eff2496ec1606a0a633cfe3693af1b9c1 GIT binary patch literal 8986 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_br.gif b/code/web/api/data/css/skin_br.gif new file mode 100644 index 0000000000000000000000000000000000000000..3a01335f8780d044591538ca6f1feddb5da63987 GIT binary patch literal 130 zcmZ?wbhEHbDEgwtm8XB6Knp#>~+S=MWIy$<#x_Wwg`uh3?1_nk(M#jd* zW@cvQ=H@mwHZCqM9v&W^o}OM_Uf$l`K0ZEvetuzLVXIcIT(f%hf69R3KSAfB)Wnk1 z6ovB4k_-iRPu~Cr#h)yUTnzRMIw0?XJj%ef>%ja14;`s~52b{YF?@`xR+wnDteSP^ zm1qlV24hU4(#C)q#zuywi4Jr4SvDQ|)2zqN>Z*LuLirjG4}Ur%8#ljzP&z9cuYiDP zORu2d#L{pECU!nyUa4+&9w7nAbmoO3qVuPFw{nR~$t+{#7Lk-*#>OcuyL1f$3oDO^ z{Jyf8OdLXT5-o=oiG^xow1m9=(cJ Sy#M7xnZ|t;rN@p84AuaFuAIF9 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_header_m.gif b/code/web/api/data/css/skin_header_m.gif new file mode 100644 index 0000000000000000000000000000000000000000..48d539173dcce5c8188433c200787243f2f03a70 GIT binary patch literal 6290 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_header_r.gif b/code/web/api/data/css/skin_header_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..c8711c2f5f1587017fa67e20c9c037e288242e91 GIT binary patch literal 977 zcmZ?wbhEHblwwd|I2OnN1cHKsLPA2qKqM?IA|fItCMF>vAt@;-B_$;-EiEG>BPS;( zFE6j4prELzsHCK%tgNh}qN1v*s-~ugwj^=I-w9;o;%w>FMR=+9#|=kMh59a z>z^=j5<^SCwCOWu&I*{)#Kg+P!ZM$QnRPKE|LFl++}6& z&1vEn6BM>$<6!6D;QYsFQlP@ZUNu)EWWs|6_9g*krwJO3Oh-9IwS*)dE?``!z$>cc za-h+{gI?w$$O5B=b{#lZ-TR5|1I=wRPGRt_Mi6P#KC5^)m=xoUr$)Xa!yeFL-&SVj?C-= zasjIMbXb@Ij+mR>nQ)lT=FNh`&3twphj}?41u!$1*Az4JS=y{{=Cdfcq1dtWc{%2p%H!C(ylF07L= literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_l.gif b/code/web/api/data/css/skin_l.gif new file mode 100644 index 0000000000000000000000000000000000000000..4ca369db55d140217b76dca67b0ab33bb7844a97 GIT binary patch literal 477 zcmZ?wbhEHbgwtm8XB6Kn%dghIyySKy1M%M`UVCDhK7d5#>OTlCKeVJ zmX?-wc6LrqPA)DkuCA^g9v)s^UOqlPK|w*m!NFl+Vd3H75fKrQk&)5S(Q$EciHV78 zRg{m>!;fF;_d`r(SPPr(wPwzrj!vm`w=Pvs>yy)7+wlBBB zizA#bTqrM`x1_VlHK~swZesmJo^a0A@Ro@=69s2Ph6~h$tAvX$j$SoUEnGTWC%k&1 z-qMM>;WFX;YYJl~3Wv`tES;D?Q8fJ2M5*=R65-n6>n5s)tDasxv18)o!i3|qA5T0` z*fufh-olfMCeD2Qv}a2Af{72G-LrFMBW8<5B)dq1##K{2?3OsW-YO eC*Ba{+V?4@Ym0`^uA2EqT7u6$PMD~`U=0B4tiwnE literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_r.gif b/code/web/api/data/css/skin_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..3c821e89e4a67edf7d368131a588908ed5d46730 GIT binary patch literal 488 zcmZ?wbhEHbgpOA8k(A#T3TA#+S)ogI=Z^L`uh3?1_p+PhQ`Lm zCMG5p78aJ4mUeb_PEJlPE-tRFt{xs9US3{4K0ZM~LBYYnVPRq6;o%Vx5s{IR(b3T{ zF)?v*afykEYgVuRPaIJEC+J+1npl#WqEMb$lA+-4=^MbH_>+Z^i@}~j2jo4FM;X{Y z91v0vn!s3RpSZNbhsnTaNr7;w*D9wKfm{g*^W)!Nv;3jA@76MbPr3{CuU`M^^sia_ zroVrj{Uh$U6H`1(T5dd7JV!-)TLVK^Uv*!4A7}iuzN9RM+P=I#;nu#&KJ|Fbc#U}7 zc&T{Vc$x0SiOu#biIzi0N8-SLuThx^XPOqku#S3f&5 zX2$GEH{*HZo94x{Z|!U8<9j`O;l$}LYo1-1eY`LAP5htP^UX3JEjl;RT%B>JN{P_% xi5*paR*Y9l-+FiItL&@!A@qowqx;0ZJrU13rYdvC7g=gqoSV2!&5?n@8URHI!gK%t literal 0 HcmV?d00001 diff --git a/code/web/api/data/css/skin_t.gif b/code/web/api/data/css/skin_t.gif new file mode 100644 index 0000000000000000000000000000000000000000..aefc8416b8729639f13683008efe2d2c8ffbc3d2 GIT binary patch literal 315 zcmZ?wbhEHbY+&GEXc1um0zpARAt4|F0%2h=76t+lAOZpqAqqsIKqM+A21H`g($XFt z9&1*w{!au@{3qyKl$uzQnxasiS(2gP?&%xAp!k!8k&8i|K?h_#$RP}@iyx@>rDV>_ zShX(a^}Yg~^Ch|WE7rYNd+`6jf&vd6ss0m7iah67%)hXr#A|KT`WtJ?yk+^A8jmIx zXms;;w>s$tSV;6cA9`pZ!PDJt;aj%kaxxn;9}BMlA6F_bZ&^=94__fOcTY-sCR-A5G*1U)9LQh>7IA@-o~!37FjxJ$8Kl4=Yr(+6Ddn)xOOU}D E0EFKz)c^nh literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/bg.jpg b/code/web/api/data/img/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d07d98c7305c75d6f8c4250fac185554f142997 GIT binary patch literal 50750 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

H99>k}TzJC8VOquNA^4DE7>_z4jS)uK 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 HI5&=x7E`Osn*XfZQXE|?ya?i_-T{j9RNnzS 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/de.png b/code/web/api/data/img/lang/de.png new file mode 100644 index 0000000000000000000000000000000000000000..767abe088625c523ca3c3114faa767f325823330 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^VnEEt!3HF?4d0vvQY^(zo*^7SP{WbZ0pxQQctjQh z)n5l;MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1T&JY5_^ zEPAhAG!#9cz|-+oAKh(LZ(9#_LLviy^OfQ(f-{$^N44!5?rOG_RU%-yEHJq(AXws T{e`}CpluAEu6{1-oD!M3ZN00004b3#c}2nYxW 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/ru.png b/code/web/api/data/img/lang/ru.png new file mode 100644 index 0000000000000000000000000000000000000000..53aaf57be4dab480ddd03e66d93f7977186a3b41 GIT binary patch literal 2886 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 literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/lang/sp.png b/code/web/api/data/img/lang/sp.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef5123baf49a626da76ae7d1ed3d577d36c7dbc GIT binary patch literal 62 zcmZ?wbhEHb6l36Hn8*ME|NsC0^N-;_GlLF@2NGvs5}(t*^7LE&xihxh>fU^B&u{*+ MiyqU`LKqmV0bcYL8UO$Q literal 0 HcmV?d00001 diff --git a/code/web/api/data/img/logo.gif b/code/web/api/data/img/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..adc59fd290006dd520a30c7ed83ac5bad30e815a GIT binary patch literal 6763 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 \ No newline at end of file diff --git a/code/web/api/player_auth.php b/code/web/api/player_auth.php new file mode 100644 index 000000000..984a96fe7 --- /dev/null +++ b/code/web/api/player_auth.php @@ -0,0 +1,44 @@ +. + */ + +require_once('ryzom_api.php'); +$cid = ryzom_get_param('cid'); +$name = ryzom_get_param('name'); +$authserver = ryzom_get_param('authserver'); +$authkey = ryzom_get_param('authkey'); + +if ($authserver) { + if (ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey)) + die('1'); + die('0'); +} + +if (RYZOM_IG || ryzom_get_param('ig')) { + echo 'ig'; + if (ryzom_authenticate_ingame($cid, $name, $authkey)) { + echo 'ok'; + $user_infos = ryzom_user_get_info($cid); + echo ryzom_get_user_id($cid, $name, $user_infos['creation_date']); + die('1'); + } + die('0'); +} else { + echo ryzom_authenticate_with_session($name, $cid, $_RYZOM_API_CONFIG['base_url'].'index.php'); +} + +?> diff --git a/code/web/api/ryzom_api.php b/code/web/api/ryzom_api.php new file mode 100644 index 000000000..960405b03 --- /dev/null +++ b/code/web/api/ryzom_api.php @@ -0,0 +1,49 @@ +. + */ + +session_start(); + +// Global defines +if (!defined('ON_IPHONE')) { + if(isset($_SERVER['HTTP_USER_AGENT'])) + define('ON_IPHONE', strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')); + else + define('ON_IPHONE', false); +} +if (!defined('RYZOM_IG')) { + if (isset($_SERVER['HTTP_USER_AGENT'])) + define('RYZOM_IG', strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')); + else + define('RYZOM_IG', false); +} + +$includes = array('auth', 'config', 'utils', 'user'); + +foreach ($includes as $include) { + if ($_SERVER['HTTP_HOST'] == 'shard.nuneo.org' || $_SERVER['HTTP_HOST'] == 'app.ryzom.com') + require_once("server/$include.php"); + else + require_once("client/$include.php"); + + require_once("common/$include.php"); +} + +require_once("common/db_lib.php"); +require_once("common/render.php"); + +?> diff --git a/code/web/api/server/auth.php b/code/web/api/server/auth.php new file mode 100644 index 000000000..a8706fe8d --- /dev/null +++ b/code/web/api/server/auth.php @@ -0,0 +1,111 @@ +. + */ + +function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { + $rawkey = RYAPI_COOKIE_KEY.$name.$cid.$authserver; + $authkey = md5($rawkey); + if ($authkey != $authkey) return false; + return true; +} + +function ryzom_authenticate_ingame($cid, $name, $authkey) { + return file_get_contents(RYAPI_AUTH_SCRIPT) == '1'; +} + +// take the character name and the account password and check if it's valid +function ryzom_authenticate_with_char_and_password($character, $password, &$cid) { + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_RING); + $char = mysql_real_escape_string($character, $db->_connection); + $sql = "SELECT char_id, char_name, user_id, home_mainland_session_id FROM characters WHERE char_name = '$char'"; + $row = $db->query_single_row($sql); + $character = $row['char_name']; + $cid = $row['char_id']; + $uid = $row['user_id']; + mysql_select_db('nel', $db->_connection); + $sql = "SELECT Password FROM user WHERE UId = $uid"; + $row = $db->query_single_row($sql); + $ok = $row['Password'] == crypt($password, $row['Password']); + return $ok; +} + +function ryzom_authenticate_with_session(&$name, &$cid, &$error_message) { + $c = ''; + + $action = ryzom_get_param('action'); + if ($action == 'logout') { + unset($_SESSION['name']); + unset($_SESSION['cid']); + } + + if (isset($_SESSION['name']) && ($name == '' || $_SESSION['name'] == $name)) { + $name = $_SESSION['cid']; + $cid = $_SESSION['cid']; + return true; + } + + $char = ryzom_get_param('char'); + $password = ryzom_get_param('password'); + + if ($char && $password) { + // check credentials + if (ryzom_authenticate_with_char_and_password($char, $password, $cid)) { + $_SESSION['name'] = $char; + $_SESSION['cid'] = $cid; + return true; + } else { + $error_message = 'bad_auth'; + } + } + + return false; +} + + + +function ryzom_get_user_id($cid, $name, $creation_date) { + $name = strtolower($name); + + $db = ryDB::getInstance('webig'); + $db->setDbDefs('players', array('id' => SQL_DEF_INT, 'cid' => SQL_DEF_INT, 'name' => SQL_DEF_TEXT, 'creation_date' => SQL_DEF_DATE, 'deleted' => SQL_DEF_BOOLEAN)); + + $charProps = $db->querySingle('players', array('cid' => intval($cid), 'deleted' => 0)); + // new char => create record + if (!$charProps) { + $charProps = array('name' => $name, 'cid' => $cid, 'creation_date' => $creation_date, 'deleted' => 0); + $charProps['id'] = $db->insert('players', $charProps); + if (!$charProps['id']) + die('ryDb New Char Error'); + } else { + // char renamed => update record + if ($charProps['name'] != $name) + if (!$db->update('players', array('name' => $name), array('id' => $charProps['id']))) + die('ryDb Rename Char Error'); + + // char deleted and recreated => change to deleted + if ($charProps['creation_date'] != $creation_date) { + if (!$db->update('players', array('deleted' => 1), array('id' => $charProps['id']))) + die('ryDb Delete char Error: '.$db->getErrors()); + $charProps = array('name' => $name, 'cid' => $cid, 'creation_date' => $creation_date, 'deleted' => 0); + if (!$charProps['id'] = $db->insert('players', $charProps)) + die('ryDb New Char in Slot Error'); + } + } + return $charProps['id']; +} + +?> diff --git a/code/web/api/server/config.php.default b/code/web/api/server/config.php.default new file mode 100644 index 000000000..c55cf74f0 --- /dev/null +++ b/code/web/api/server/config.php.default @@ -0,0 +1,31 @@ +. + */ +define('RYAPI_WEBDB_HOST', 'localhost'); +define('RYAPI_WEBDB_LOGIN', 'localhost'); +define('RYAPI_WEBDB_PASS', 'localhost'); + +define('RYAPI_NELDB_HOST', 'localhost'); +define('RYAPI_NELDB_LOGIN', 'shard'); +define('RYAPI_NELDB_PASS', 'localhost'); +define('RYAPI_NELDB_RING', 'ring_open'); +define('RYAPI_NELDB_NEL', 'nel'); + +define('RYAPI_AUTH_SCRIPT', ''); +define('RYAPI_COOKIE_KEY', ''); + +?> diff --git a/code/web/api/server/user.php b/code/web/api/server/user.php new file mode 100644 index 000000000..9124191ae --- /dev/null +++ b/code/web/api/server/user.php @@ -0,0 +1,111 @@ +. + */ + +function ryzom_user_get_info($cid) { + // User information + global $_RYZOM_API_CONFIG; + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_RING); + $sql = "SELECT char_name, race, civilisation, cult, guild_id, creation_date, last_played_date FROM characters WHERE char_id = $cid"; + $result = $db->query($sql) or die('Could not query on ryzom_user_get_info'); + $found = $db->num_rows($result) >= 1; + if (!$found) + die('Could not found on ryzom_user_get_info'); + $row = $db->fetch_assoc($result); + $db->free_result($result); + if ($row) { + $row['race'] = substr($row['race'], 2); + $row['cult'] = substr($row['cult'], 2); + $row['civ'] = substr($row['civilisation'], 2); + if ($row['guild_id'] != '0') { + //$xml = @simplexml_load_file(ryzom_guild($row['guild_id'], false)); + $xml = false; + if ($xml !== false) { + $row['guild_icon'] = (string)$xml->icon; + $row['guild_name'] = (string)$xml->name; + $result = $xml->xpath("/guild/members/member[cid=$cid]"); + while(list( , $item) = each($result)) + $row['grade'] = (string)$item->grade; + } else { + $row['guild_name'] = 'UNKNOWN_GUILD_'.$row['guild_id']; // Unknow name (normal in yubo shard) + } + } + } + + $uid = intval($cid / 16); + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_NEL); + $sql = "SELECT Privilege FROM user WHERE UId = $uid"; + $result = $db->query($sql) or die("Could not query."); + $priv_row = $db->fetch_row($result, MYSQL_NUM); + $priv = $priv_row[0]; + $db->free_result($result); + $groups = array(); + + if (strpos($priv, ':DEV:') !== false) { + $groups[] = 'DEV'; + $groups[] = 'SGM'; + $groups[] = 'GM'; + $groups[] = 'EM'; + $groups[] = 'EG'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':SGM:') !== false) { + $groups[] = 'SGM'; + $groups[] = 'GM'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':GM:') !== false) { + $groups[] = 'GM'; + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':VG:') !== false) { + $groups[] = 'VG'; + $groups[] = 'G'; + } + + if (strpos($priv, ':G:') !== false) { + $groups[] = 'G'; + } + + if (strpos($priv, ':SEM:') !== false) { + $groups[] = 'SEM'; + $groups[] = 'EM'; + $groups[] = 'EG'; + } + + if (strpos($priv, ':EM:') !== false) { + $groups[] = 'EM'; + $groups[] = 'EG'; + } + + if (strpos($priv, ':EG:') !== false) { + $groups[] = 'EG'; + } + + $groups[] = 'PLAYER'; + $row['groups'] = $groups; + + return $row; +} + +?> diff --git a/code/web/api/server/utils.php b/code/web/api/server/utils.php new file mode 100644 index 000000000..49860d24e --- /dev/null +++ b/code/web/api/server/utils.php @@ -0,0 +1,49 @@ +. + */ + + +function ryzom_name_to_file($name) +{ + $r = ''; + for ($i=0; $i= chr(127)) + $r .= sprintf("%%%02x", ord($name[$i])); + else + $r .= $name[$i]; + } + return $r; +} + +// ------------------------------------- +// get user home directory +// ------------------------------------- +function ryzom_get_user_dir($user) +{ + global $_RYZOM_API_CONFIG; + + if ($user == "") + die("INTERNAL ERROR CODE 1"); + + $user = ryzom_name_to_file($user); + return $_RYZOM_API_CONFIG['cookie_path'].'/'.$_RYZOM_API_CONFIG['shardid'].'/'.substr(strtolower($user), 0, 2).'/'.strtolower($user).'/'; +} + +?> diff --git a/code/web/app/app_test/favicon.png b/code/web/app/app_test/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..623a566634f032975e9ecd1bdd7a01fb34995cb3 GIT binary patch literal 2596 zcmWlbdpy(K1IL$yP|2fAk9%UIJXpx3h_Pve%tH^cWp0UFrgF`t$)#yL6dqQ}grD2w zHjOfpRu)T3%ca&(nvs}Xf2TjrIj`4web4t?KA+F~oGdq2r(LoKWFZj9E)>$i1GJjI zi;NVgW8&j~f@bGsq)!Y4BB%JfY#Sa+UI%^eP!4vU-ptB7r^8hRB}5AS3Z|v=(iPrw zVO(zHdyD<9wprRreFb)>Y;BRbw;g4&RI)~Cw!tw$-qC~KZth^2B2AHoj`w^Jjq;6J zI7tcn@1)2qQxZ=&=h`X4j1a8kI4P+;n)uYch37m!>6iUaq=Al#L7P^a9L;4bzYcm=G2CmfDw`x@7|(zVAnkw$7B{Vpsl zEMy1-cz@1gr{w}yX*ZbCmoq1ReZjTyHta3SHl=y3($Z2=Upx&EmSsT!0T2#+2)>K? z7qW^YziZd0wG#;m3E>eDw6-><+L8G7R2?wo2v4~DcM*O=@Y;N0y<3lxXtL@8@lV-k zSsilHVAzMRw`+C-H_EAg;woH z=4a@j9EMO5G{fx*2y#0&W%;KK27{{f$j!~wWJL#Gx+I(!Pubeo^6~Y}Jv1S{HeGf_ zH#0LcQm0^`BSAd(iGI{hL7~6t#R^;z3(ekhv4qIC_&okq3?XM!!0u89e*T0D;}WVo zs@M6M8p-WO%CbAYPEJm?gqvCM!dhg~AmE5}6z@{?lh?M6uy6!IVW7#t)29%lC-V{m zfr=cskGJ>J)=LZD8-RL1k=(pIwz`_y#@YLBxBmrtFvS}uUD0UksMy$y`q>#ei5dzj zEcBs=e)+X2m6F%Gt(O+R)iz|?`X??RYDNsc#+F><);BdbryH^!azcm9iP)PWDLdN} zlsndJxqs^3ZPk>PmcF}?XJb}9OAjgW=lZxS9rdI47Mlip`}^w^I!7&i!^}-|=Uw9Y z(qngGFe++lhYAJ)pi*b77bN|YmiE~xXrdHphJPT)u(6eul`m6M)XMnsDyoP6YntJZ zAYbQxjX{=!1ba~??RrET>+BhuzKmFlm$QM5494qc z&$f~H3W&Y*`k1L#DpONacgxH7@APfIoSJxo{o%ubN{=j9_Dw#N*BaW!gFJ#1;juh3 zP(h`LSOv*#R#sMDqK^j!1D9Ni?V`F}nWu$xKM%kHIXfBCFYia3QU$@T5$$3FT zH+erC4ab$}=IiX0+(r$>L7$@_U~O}A+=S53tfnU8G)>68(eNMqyptXVg_3V+h9`TL zK=(_536ID7*ZI&O<>VQ&(#o-j=EsjS@IK$?=6*~*+wLBgdR?^kbDyz{gqfMy8$wyQ z*=ZJb1^4f3t)^FMJgKRfp}Q&} zw8@LpY|iY`WmS;uU!O8H-VoIKqg*9xC$`trY-)FFWk>g9Fq!rsarS1VcpNS*&?F1* zQ=w(UP6(vApwSBbjon*YkjK1BadB}k0!@H!z>Fhdg%NFs$M@OXgUQ}Fl^WLaQoy=1 zAc+3>u3H3j#-hI5HDEoVbN~# z?`p~b*F|@{5>KQUIn2z=$bg8QJ9mmpux2v}W0{BMt@B{nP$&}Ep-Tgt-;J=oD70?D zeXrWAaGr2~XJ;qaNjNVEr)?CXf-t6rex@IFS8}gaGqr%q5eRFL`K+>!!d!!;ov3_Yb8%HHU~-gj&7qSFsNYHn^` zSY)3}nSFli&y*x#3wQHTXvvT;?uI8|e*>5Kmwe)c9vOMtxiZ7?zt-;?P4zI@GS|#= zb-KAZcpu;@;63rzD$3?k$8>q;F)OP-Pe-XXcXzW7H#{*p0f+w-8FjD!=>A5J$i%|d zC+FuI749U9mm2`GIjdb~Op0|V><2K}N)K>h^gR|X#h0;9ZmoBRwS1s7_;)8;96$bR zJ_Ni>bQw$U{<%QnKiM2UZM4Da>FL246gt0eJu=$5aT71cRNxZ6##+X90vzuq@vU*; zu1yD*t=VJa<6Rql%KqzZp(T{0^@V;XaN{pT?yi!SmQI|1COs8QNm{-NB~Hh5d^}}R zjIORR(9iyHQ*l`>VnRs7u5^}KkvN8h&ZXHE>+`F#4I;+cT<2hKZ?A|#T62!u+Dz*D zHT5SUDakKJ)#;PSn;J?CW|uF4pN?u$*jtXhn^N&LN!XXfJZbRkgP;(u4)v!3(*6(b CVj7bG literal 0 HcmV?d00001 diff --git a/code/web/app/app_test/index.php b/code/web/app/app_test/index.php new file mode 100644 index 000000000..95573dfe2 --- /dev/null +++ b/code/web/app/app_test/index.php @@ -0,0 +1,34 @@ +enable = true; + +// Debug log +p($user); + +// Update user acces on Db +$db = ryDB::getInstance(APP_NAME); +$db->setDbDefs('test', array('id' => SQL_DEF_INT, 'num_access' => SQL_DEF_INT)); + +$num_access = $db->querySingleAssoc('test', array('id' => $user['id'])); +if ($num_access) + $db->update('test', array('num_access' => ++$num_access['num_access']), array('id' => $user['id'])); +else + $db->insert('test', array('num_access' => $num_access['num_access']=1, 'id' => $user['id'])); + +// Content +$c = _t('access', $num_access['num_access']).'
'; + +echo ryzom_app_render(APP_NAME, $c); + +?> diff --git a/code/web/app/app_test/lang.php b/code/web/app/app_test/lang.php new file mode 100644 index 000000000..0a877c548 --- /dev/null +++ b/code/web/app/app_test/lang.php @@ -0,0 +1,15 @@ + + array ( + 'en' => 'User access this page %s times', + 'fr' => 'L\'utilisateur a accede a cette page %s fois', + 'de' => '', + 'ru' => '', + ), +); +if(isset($ryzom_texts)) + $ryzom_texts = array_merge ($__texts, $ryzom_texts); +else + $ryzom_texts = $__texts; +?> \ No newline at end of file diff --git a/code/web/app/config.php.default b/code/web/app/config.php.default new file mode 100644 index 000000000..0ecb2c302 --- /dev/null +++ b/code/web/app/config.php.default @@ -0,0 +1,26 @@ +. + */ + +define('RYAPP_URL', 'http://'); +define('RYAPP_PATH', dirname(__FILE__).'/'); +define('RYAPI_PATH', dirname(__FILE__).'/../api/'); + +include_once(RYAPI_PATH.'ryzom_api.php'); + +?> diff --git a/code/web/app/index.php b/code/web/app/index.php new file mode 100644 index 000000000..ed90c42b2 --- /dev/null +++ b/code/web/app/index.php @@ -0,0 +1,35 @@ +'._t('welcome', $user['char_name']).''; +} else { + if (!RYZOM_IG) { + if ($user['message']) + $c .= '

'._t($user['message']).'

'; + $c .= ryzom_render_login_form(ryzom_get_param('name')); + } +} + +foreach ($apps as $app) { + $c .= ''._t($app).'
'; +} + +if($logged) $c .= '
'._t('logout').''; + +echo ryzom_app_render('Ryzom', $c); + +?> \ No newline at end of file diff --git a/code/web/app/lang.php b/code/web/app/lang.php new file mode 100644 index 000000000..4780fcd00 --- /dev/null +++ b/code/web/app/lang.php @@ -0,0 +1,371 @@ + + array ( + 'en' => 'Welcome %s', + 'fr' => 'Bienvenue %s', + 'de' => 'Willkommen %s', + 'ru' => 'Добро пожаловать %s', + ), + 'latest_news_rp' => + array ( + 'en' => 'Latest RP news', + 'fr' => 'Dernières nouvelles RP', + 'de' => 'Letzte RP-Nachrichten', + 'ru' => 'Ролевые новоÑти', + ), + 'latest_news_off' => + array ( + 'en' => 'Latest Ryzom news', + 'fr' => 'Dernières nouvelles de Ryzom', + 'de' => 'Letzte Ryzom-Nachrichten', + 'ru' => 'ПоÑледние новоÑти Ризома', + ), + 'avail_apps' => + array ( + 'en' => 'Available applications', + 'fr' => 'Applications disponibles', + 'de' => 'Verfügbare Anwendungen', + 'ru' => 'ДоÑтупные приложениÑ', + ), + 'home' => + array ( + 'en' => 'Home', + 'fr' => 'Accueil', + 'de' => 'Home', + 'ru' => 'К началу', + ), + 'logout' => + array ( + 'en' => 'Log out', + 'fr' => 'se déconnecter', + 'de' => 'Ausloggen', + 'ru' => 'Выйти', + ), + 'by' => + array ( + 'en' => 'by', + 'fr' => 'par', + 'de' => 'von', + 'ru' => 'Ñообщение', + ), + 'date_format' => + array ( + 'en' => '%1$s %2$s %3$s', + 'fr' => '%3$s %1$s %2$s', + 'de' => '%3$s %1$s %2$s', + 'ru' => '%1$s %2$s %3$s', + ), + 'ago' => + array ( + 'en' => 'ago', + 'fr' => 'il y a', + 'de' => 'Vor', + 'ru' => 'назад', + ), + 'to_go' => + array ( + 'en' => 'to go', + 'fr' => 'dans', + 'de' => 'In', + 'ru' => 'оÑталоÑÑŒ', + ), + 'posted' => + array ( + 'en' => 'Posted', + 'fr' => 'Posté', + 'de' => 'Geschrieben', + 'ru' => 'Отправлено', + ), + 'error_auth' => + array ( + 'en' => 'Please press the Refresh button to display the homepage.', + 'fr' => 'Cliquez sur le bouton Rafraichir pour afficher la page d\'accueil.', + 'de' => 'Um auf die Hauptseite zu gelangen drücke bitte auf Aktualisieren.', + 'ru' => 'Ð”Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð¾Ð¼Ð°ÑˆÐ½ÐµÐ¹ Ñтраницы нажмите кнопку "Обновить"', + ), + 'submit' => + array ( + 'en' => 'Submit', + 'fr' => 'Envoyer', + 'de' => 'Absenden', + 'ru' => 'Отправить', + ), + 'enter_key' => + array ( + 'en' => 'Please enter the full character API Key that you can find on your profile page', + 'fr' => 'Entrez la clé d\'API complète de votre personnage que vous trouverez sur votre page de profil', + 'de' => 'Gib bitte den lompletten Charakter-API-Schlüssel ein, diesen findest du auf deiner Profilseite', + 'ru' => 'ПожалуйÑта, введите полный API Ключ, который вы можете получить по адреÑу your profile page', + ), + 'enter_shard' => + array ( + 'en' => 'Select the server of your character', + 'fr' => 'Sélectionnez le serveur où se trouve votre personnage', + 'de' => 'Wähle den Server deines Charakters aus', + 'ru' => 'Выбрать Ñервер', + ), + 'enter_char' => + array ( + 'en' => 'Enter your CHARACTER name (*not* your account name)', + 'fr' => 'Saisissez le nom de votre PERSONNAGE (pas votre nom de compte)', + 'de' => 'Gib den Namen deines CHARAKTERS ein (*nicht* deinen Account-Namen)', + 'ru' => 'Введите Ð¸Ð¼Ñ ÐŸÐ•Ð Ð¡ÐžÐÐЖР(*не* Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ)', + ), + 'enter_password' => + array ( + 'en' => 'Enter the password of your ACCOUNT', + 'fr' => 'Saisissez le mot de passe de votre COMPTE', + 'de' => 'Gib das Passwort deines ACCOUNTS ein', + 'ru' => 'Введите пароль Ñвоей УЧЕТÐОЙ ЗÐПИСИ', + ), + 'bad_login_password' => + array ( + 'en' => 'Cannot login. Perhaps you entered a bad password or you didn\'t use your CHARACTER name.', + 'fr' => 'Connexion impossible. Peut-être avez vous saisi un mauvais mot de passe ou vous n\'avez pas utilisé le nom de votre PERSONNAGE.', + 'de' => 'Login fehlgeschlagen. Vielleicht hast du ein falsches Passwort eingegeben oder du hast nicht deinen CHARAKTER-Namen verwendet.', + 'ru' => 'Ðевозможно подключитьÑÑ. Возможно, вы иÑпользовали неверный пароль или Ð¸Ð¼Ñ ÐŸÐ•Ð Ð¡ÐžÐÐЖÐ.', + ), + 'app_notes' => + array ( + 'en' => 'Notepad', + 'fr' => 'Bloc Note', + 'de' => 'Notizblock', + 'ru' => 'Блокнот', + ), + 'app_news' => + array ( + 'en' => 'News', + 'fr' => 'Nouvelles', + 'de' => 'News', + 'ru' => 'ÐовоÑти', + ), + 'app_mail' => + array ( + 'en' => 'Mail', + 'fr' => 'Courrier', + 'de' => 'Mail', + 'ru' => 'Почта', + ), + 'app_patch' => + array ( + 'en' => 'Atysmas', + 'fr' => 'Noel', + 'de' => 'Weihnachten', + 'ru' => 'Christmas', + ), + 'app_wiki' => + array ( + 'en' => 'Atys Wiki', + 'fr' => 'Lore & Chroniques', + 'de' => 'Atys Wiki', + 'ru' => 'Wiki ÐтиÑа', + ), + 'app_bots' => + array ( + 'en' => 'Bots', + 'fr' => 'Bots', + 'de' => 'Bots', + 'ru' => 'Боты', + ), + 'app_test' => + array ( + 'en' => 'Test Application', + 'fr' => 'Application de test', + 'de' => '', + 'ru' => '', + ), + 'app_forum' => + array ( + 'en' => 'Forums', + 'fr' => 'Forums', + 'de' => 'Foren', + 'ru' => 'Форумы', + ), + 'app_translate' => + array ( + 'en' => 'Translate', + 'fr' => 'Traduction', + 'de' => 'Ãœbersetzen', + 'ru' => 'Перевод', + ), + 'app_race' => + array ( + 'en' => 'Race', + 'fr' => 'Course', + 'de' => 'Rennen', + 'ru' => 'Гонка', + ), + 'app_poll' => + array ( + 'en' => 'Polls', + 'fr' => 'Sondages', + 'de' => 'Polls', + 'ru' => 'ГолоÑование', + ), + 'app_zapping' => + array ( + 'en' => 'Atysmas', + 'fr' => 'Atysmas', + 'de' => 'Atysmas', + 'ru' => 'ÐтиÑмаÑ', + ), + 'latest_blog' => + array ( + 'en' => 'Latest news from the dev blog', + 'fr' => 'Dernières nouvelles du blog des dév', + 'de' => 'Aktuelles aus dem Dev-Blog', + 'ru' => 'ПоÑледние новоÑти Дневника разработчиков', + ), + 'app_profile' => + array ( + 'en' => 'Profile', + 'fr' => 'Profil', + 'de' => 'Profile', + 'ru' => 'Личные данные', + ), + 'next_events' => + array ( + 'en' => 'Next events', + 'fr' => 'Prochains événements', + 'de' => 'Nächste Events', + 'ru' => 'Ближайшие ÑобытиÑ', + ), + 'absolute_date_format' => + array ( + 'en' => '%2$s, %1$s %3$s', + 'fr' => '%2$s %1$s %3$s', + 'de' => '%2$s %1$s %3$s', + 'ru' => '%2$s, %1$s %3$s', + ), + 'app_craft' => + array ( + 'en' => 'Craft: Recipe-Book', + 'fr' => 'Craft : Livre de recettes', + 'de' => 'Craft: Recipe-Book', + 'ru' => 'РемеÑло: чертежи', + ), + 'app_ryzhome' => + array ( + 'en' => 'RyzHome', + 'fr' => 'Mon appart', + 'de' => 'Meine Wohnung', + 'ru' => 'Мой Дом', + ), + 'app_event' => + array ( + 'en' => 'Event Pad', + 'fr' => 'Pad Event', + 'de' => 'Event-Pad', + 'ru' => 'СобытиÑ', + ), + 'app_calendar' => + array ( + 'en' => 'Calendar', + 'fr' => 'Calendrier', + 'de' => 'Kalender', + 'ru' => 'Календарь', + ), + 'app_contest' => + array ( + 'en' => 'Contest', + 'fr' => 'Concours', + 'de' => 'Contest', + 'ru' => 'конкурÑ', + ), + 'app_rpjobs_v2' => + array ( + 'en' => 'Occupations', + 'fr' => 'Métiers', + 'de' => 'Berufe', + 'ru' => 'ЗанÑтиÑ', + ), + 'app_rewards' => + array ( + 'en' => 'Rewards', + 'fr' => 'Récompenses', + 'de' => 'Belohnungen', + 'ru' => 'Ðаграды', + ), + 'admin_apps' => + array ( + 'en' => 'Ryzom Team Apps', + 'fr' => 'Applications Pour L\'équipe Ryzom', + 'de' => 'Ryzom Team Apps', + 'ru' => 'Ryzom Team Apps', + ), + 'dev_apps' => + array ( + 'en' => 'Devs Apps (don\'t use!)', + 'fr' => 'Applications Devs (Ne pas utiliser !)', + 'de' => 'Devs Apps (don\'t use!)', + 'ru' => 'Devs Apps (don\'t use!)', + ), + 'app_admin' => + array ( + 'en' => 'Administration', + 'fr' => 'Administration', + 'de' => '{app_admin}', + 'ru' => '{app_admin}', + ), + 'testing_apps' => + array ( + 'en' => 'Testing Apps (don\'t use without permission)', + 'fr' => 'Applications en test (N\'utilisez que si vous y êtes invité)', + 'de' => 'Testing Apps (don\'t use without permission)', + 'ru' => 'Testing Apps (don\'t use without permission)', + ), + 'app_arcc' => + array ( + 'en' => 'A.R.C.C.', + 'fr' => 'A.R.C.C.', + 'de' => 'A.R.C.C.', + 'ru' => 'A.R.C.C.', + ), + 'link_to_forum' => + array ( + 'en' => 'Show details in forum', + 'fr' => 'Voir détails sur le forum', + 'de' => 'Zeige Details im Forum', + 'ru' => '', + ), + 'aura_and_powers_reseted' => + array ( + 'en' => 'Your auras and powers have been reset. They can be reset again in 2 hours.', + 'fr' => 'Vos auras et pouvoirs ont été remis à zéro. Prochaine remise à zéro dans 2h.', + 'de' => 'Deine Auren und Kräfte wurden zurückgesetzt. Sie können erst in 2 Stunden erneut zurückgesetzt werden.', + 'ru' => '', + ), + 'pvp_reseted' => + array ( + 'en' => 'Your PvP timers have been reset. ', + 'fr' => 'Votre tag pvp à été remis à zéro.', + 'de' => 'Deine PvP-Timer wurden zurückgesetzt.', + 'ru' => '', + ), + 'temporary_fixes' => + array ( + 'en' => 'Temporary Fixes', + 'fr' => 'Correctifs temporaires', + 'de' => 'Temporäre Fixes', + 'ru' => '', + ), + 'aura_and_powers_wait' => + array ( + 'en' => 'Please wait %d min for next reset', + 'fr' => 'Merci d\'attendre %d minutes avant une nouvelle remise à zéro', + 'de' => 'Please wait %d min for next reset', + 'ru' => '', + ), + 'app_power_reset' => + array ( + 'en' => 'Reset of Aura and Powers', + 'fr' => 'Reset des Auras et Pouvoirs', + 'de' => 'Auren und Kräfte zurücksetzen', + 'ru' => '', + ), +); +if(isset($ryzom_texts)) + $ryzom_texts = array_merge ($__texts, $ryzom_texts); +else + $ryzom_texts = $__texts; From 6b4186eaed51e50cb81a4f788897838d9fc629d8 Mon Sep 17 00:00:00 2001 From: sfb Date: Fri, 4 May 2012 08:58:52 -0500 Subject: [PATCH 19/66] Fixed: #1465 Added debugging flag to NL_DEBUG_CFLAGS. --- code/CMakeModules/nel.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index e6bf57101..9e06b8ce0 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -519,7 +519,7 @@ MACRO(NL_SETUP_BUILD) ENDIF(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") ENDIF(WITH_SYMBOLS) - SET(NL_DEBUG_CFLAGS "-DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}") + SET(NL_DEBUG_CFLAGS "-g -DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}") SET(NL_RELEASE_CFLAGS "-DNL_RELEASE -DNDEBUG -O3 ${NL_RELEASE_CFLAGS}") ENDIF(MSVC) ENDMACRO(NL_SETUP_BUILD) From c813eb4b1221478b9c1ffe8f86e57bfd527eae81 Mon Sep 17 00:00:00 2001 From: vl Date: Fri, 4 May 2012 18:33:59 +0200 Subject: [PATCH 20/66] Added: external auth --- code/web/api/client/auth.php | 26 ++++++------- code/web/api/client/user.php | 18 ++++++++- code/web/api/common/auth.php | 24 ++++++++---- code/web/api/common/logger.php | 2 +- code/web/api/common/render.php | 53 ++++++++++++-------------- code/web/api/ryzom_api.php | 6 --- code/web/api/server/auth.php | 11 +++++- code/web/api/server/config.php.default | 2 + code/web/app/app_test/index.php | 2 +- code/web/app/index.php | 11 +++--- 10 files changed, 90 insertions(+), 65 deletions(-) diff --git a/code/web/api/client/auth.php b/code/web/api/client/auth.php index cab8a5886..f47dbd634 100644 --- a/code/web/api/client/auth.php +++ b/code/web/api/client/auth.php @@ -20,30 +20,28 @@ require_once(RYAPI_PATH.'client/config.php'); // Og (non-ryzom.com) method function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { - global $_RYZOM_API_CONFIG; - $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&authserver='.$authserver; - - $res = file_get_contents($fn); - return $res == '1'; } // Ig method function ryzom_authenticate_ingame($cid, $name, $authkey) { - global $_RYZOM_API_CONFIG; - $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name.'&cid='.$cid.'&authkey='.$authkey.'&ig=1'; + if (isset($_SESSION['user'])) + return true; - $res = file_get_contents($fn); - echo $res; - return $res == '1'; + if (ryzom_get_param('user')) + return true; + + return false; } // Session method function ryzom_authenticate_with_session($name, $redirect) { - global $_RYZOM_API_CONFIG; - $fn = $_RYZOM_API_CONFIG['auth_script'].'?name='.$name; + if (isset($_SESSION['user'])) + return true; - $res = file_get_contents($fn); - return $res == '1'; + if (ryzom_get_param('user')) + return true; + + return false; } ?> diff --git a/code/web/api/client/user.php b/code/web/api/client/user.php index de526dcca..b6e906b2c 100644 --- a/code/web/api/client/user.php +++ b/code/web/api/client/user.php @@ -17,7 +17,23 @@ */ function ryzom_user_get_info($cid) { - return Array(); + if (isset($_SESSION['user'])) + return $_SESSION['user']; + + $user = unserialize(base64_decode(ryzom_get_param('user'))); + $_SESSION['user'] = $user; + return $user; } +function ryzom_get_user_id($cid, $name, $creation_date) { + if (isset($_SESSION['user'])) + return $_SESSION['user']['id']; + + $user = unserialize(base64_decode(ryzom_get_param('user'))); + $_SESSION['user'] = $user; + + return $user['id']; +} + + ?> diff --git a/code/web/api/common/auth.php b/code/web/api/common/auth.php index b6bcdd799..1d52c5d8e 100644 --- a/code/web/api/common/auth.php +++ b/code/web/api/common/auth.php @@ -5,7 +5,8 @@ function ryzom_app_authenticate(&$user, $ask_login=true, $welcome_message='') { $authserver = ryzom_get_param('authserver'); $authkey = ryzom_get_param('authkey'); $lang = ryzom_get_param('lang'); - + $cid = ryzom_get_param('cid', ''); + $is_ingame = false; // we have to set the $user['lang'] even for anonymous user or we cannot display the test in the right langage if($lang == '') { $l = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); @@ -14,15 +15,20 @@ function ryzom_app_authenticate(&$user, $ask_login=true, $welcome_message='') { else $lang = 'en'; } + $user['message'] = ''; $user['lang'] = $lang; - - if (RYZOM_IG || ryzom_get_param('ig')) { + $user['ig'] = false; + + if ((isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')) || ryzom_get_param('ig')) { + $user['ig'] = true; // Ingame - $cid = ryzom_get_param('cid'); - if (!ryzom_authenticate_ingame($cid, $name, $authkey)) + $shardid = ryzom_get_param('shardid'); + if (!ryzom_authenticate_ingame($shardid, $cid, $name, $authkey)) return false; + $is_ingame = true; } else { // Outgame : Use session + $error_message = ''; if (!ryzom_authenticate_with_session($name, $cid, $error_message)) { if ($ask_login) { $c = ''; @@ -47,8 +53,12 @@ function ryzom_app_authenticate(&$user, $ask_login=true, $welcome_message='') { // get user informations $user = ryzom_user_get_info($cid); $user['lang'] = $_SESSION['lang']; - - $user['id'] = ryzom_get_user_id($cid, $user['char_name'], $user['creation_date']); + if (isset($user['creation_date'])) + $user['id'] = ryzom_get_user_id($cid, $user['char_name'], $user['creation_date']); + if ($is_ingame && $user['last_played_date'] != '0') + $user['ig'] = true; + else + $user['ig'] = false; unset($user['last_played_date']); unset($user['creation_date']); return true; diff --git a/code/web/api/common/logger.php b/code/web/api/common/logger.php index f4909e721..1e5106b54 100644 --- a/code/web/api/common/logger.php +++ b/code/web/api/common/logger.php @@ -33,7 +33,7 @@ class ryLogger { function getLogs() { $ret = ''; if ($this->logs && $this->enable) - $ret = "Debug\n".implode("\n", $this->logs); + $ret = "Debug\n\n".implode("\n", $this->logs); $this->logs = array(); return $ret; } diff --git a/code/web/api/common/render.php b/code/web/api/common/render.php index a2ec31795..60b101d38 100644 --- a/code/web/api/common/render.php +++ b/code/web/api/common/render.php @@ -16,7 +16,7 @@ * along with ryzom_api. If not, see . */ -function ryzom_app_render($title, $content, $bgcolor='', $javascript=array(), $homeLink=false) { +function ryzom_app_render($title, $content, $ig=false, $bgcolor='', $javascript=array(), $homeLink=false) { $c = ''; // Render header $title_prefix = ''; @@ -25,38 +25,35 @@ function ryzom_app_render($title, $content, $bgcolor='', $javascript=array(), $h } if (!$bgcolor) - $bgcolor = '#000000'.(RYZOM_IG?'00':''); + $bgcolor = '#000000'.($ig?'00':''); - $c .= ''."\n"; - $c .= ' - '."\n"; - $c .= ' '.$title_prefix.(translation_exists($title)?_t($title):$title).''."\n"; - $c .= ' '."\n"; - - if (!RYZOM_IG) { + if (!$ig) { + $c .= ''."\n"; + $c .= ' + '."\n"; + $c .= ' '.$title_prefix.(translation_exists($title)?_t($title):$title).''."\n"; + $c .= ' '."\n"; $c .= ryzom_render_header(); $c .= ryzom_render_header_www(); - } + $events = ON_IPHONE ? 'onorientationchange="updateOrientation();" ' : ''; + $c .= ' '."\n"; + $c .= ' '."\n"; + // Javascript + $js_code = ''; + foreach ($javascript as $js) + $js_code .= ''; + $c .= $js_code; - $events = ON_IPHONE ? 'onorientationchange="updateOrientation();" ' : ''; - - $c .= ' '."\n"; - - $c .= ' '."\n"; - - // Javascript - $js_code = ''; - foreach ($javascript as $js) - $js_code .= ''; - $c .= $js_code; - - if (RYZOM_IG) - $c .= $content; - else{ $c .= ryzom_render_www(ryzom_render_window($title, $content, $homeLink)); + $c .= ''; + } else { + $c .= ''; + $c .= $content; + $debug = ryLogger::getInstance()->getLogs(); + if ($debug) + $c .= '
'.$debug.'
'; + $c .= ''; } - - $c .= ''; return $c; } @@ -140,7 +137,7 @@ function ryzom_render_window_begin($title, $homeLink=false) { return '
-
'.$title_prefix.(translation_exists($title)?_t($title):$title).$homeLink.'
+
'.(translation_exists($title)?_t($title):$title).$homeLink.'
diff --git a/code/web/api/ryzom_api.php b/code/web/api/ryzom_api.php index 960405b03..5cd9a7ba8 100644 --- a/code/web/api/ryzom_api.php +++ b/code/web/api/ryzom_api.php @@ -25,12 +25,6 @@ if (!defined('ON_IPHONE')) { else define('ON_IPHONE', false); } -if (!defined('RYZOM_IG')) { - if (isset($_SERVER['HTTP_USER_AGENT'])) - define('RYZOM_IG', strpos($_SERVER['HTTP_USER_AGENT'], 'Ryzom')); - else - define('RYZOM_IG', false); -} $includes = array('auth', 'config', 'utils', 'user'); diff --git a/code/web/api/server/auth.php b/code/web/api/server/auth.php index a8706fe8d..2e2b3ca1c 100644 --- a/code/web/api/server/auth.php +++ b/code/web/api/server/auth.php @@ -23,8 +23,15 @@ function ryzom_authenticate_with_serverkey($cid, $name, $authserver, $authkey) { return true; } -function ryzom_authenticate_ingame($cid, $name, $authkey) { - return file_get_contents(RYAPI_AUTH_SCRIPT) == '1'; +function ryzom_authenticate_ingame($shardid, $cid, $name, $authkey) { + $db = new ServerDatabase(RYAPI_NELDB_HOST, RYAPI_NELDB_LOGIN, RYAPI_NELDB_PASS, RYAPI_NELDB_RING); + $uid = intval($cid / 16); + $sql = "SELECT cookie FROM ring_users WHERE user_id = $uid"; + $row = $db->query_single_row($sql); + + $rawkey = $shardid.$name.$cid.'\''.trim($row['cookie']).'\''; + $md5rawkey = md5($rawkey); + return $authkey == $md5rawkey; } // take the character name and the account password and check if it's valid diff --git a/code/web/api/server/config.php.default b/code/web/api/server/config.php.default index c55cf74f0..d145da877 100644 --- a/code/web/api/server/config.php.default +++ b/code/web/api/server/config.php.default @@ -15,6 +15,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with ryzom_api. If not, see . */ + +define('RYAPI_SHARDID', '101'); define('RYAPI_WEBDB_HOST', 'localhost'); define('RYAPI_WEBDB_LOGIN', 'localhost'); define('RYAPI_WEBDB_PASS', 'localhost'); diff --git a/code/web/app/app_test/index.php b/code/web/app/app_test/index.php index 95573dfe2..ad5408e22 100644 --- a/code/web/app/app_test/index.php +++ b/code/web/app/app_test/index.php @@ -29,6 +29,6 @@ else // Content $c = _t('access', $num_access['num_access']).'
'; -echo ryzom_app_render(APP_NAME, $c); +echo ryzom_app_render(APP_NAME, $c, $user['ig']); ?> diff --git a/code/web/app/index.php b/code/web/app/index.php index ed90c42b2..86223a42f 100644 --- a/code/web/app/index.php +++ b/code/web/app/index.php @@ -1,7 +1,6 @@ '._t('welcome', $user['char_name']).''; } else { - if (!RYZOM_IG) { + if (!$user['ig']) { if ($user['message']) $c .= '
'._t($user['message']).'

'; $c .= ryzom_render_login_form(ryzom_get_param('name')); @@ -28,8 +26,11 @@ foreach ($apps as $app) { $c .= ''._t($app).'
'; } -if($logged) $c .= '
'._t('logout').''; +if ($logged && !$user['ig']) + $c .= '
'._t('logout').''; -echo ryzom_app_render('Ryzom', $c); +// Print GET values on debug view +p($_GET); +echo ryzom_app_render('Ryzom', $c, $user['ig']); ?> \ No newline at end of file From 54b1709d145b1bf2c1f83c448c79eeedc03efbed Mon Sep 17 00:00:00 2001 From: kervala Date: Sun, 6 May 2012 21:50:44 +0200 Subject: [PATCH 21/66] Fixed: Compilation using WITH_STATIC_EXTERNAL under Mac OS X --- code/ryzom/CMakeLists.txt | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/code/ryzom/CMakeLists.txt b/code/ryzom/CMakeLists.txt index eb3d1c642..62323501e 100644 --- a/code/ryzom/CMakeLists.txt +++ b/code/ryzom/CMakeLists.txt @@ -7,15 +7,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/common/src ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/common ) SET(RZ_SERVER_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/server/src) -IF(WITH_STATIC) - FIND_PACKAGE(OpenSSL QUIET) - IF(OPENSSL_FOUND) - SET(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) - SET(CURL_LIBRARIES ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES}) - ENDIF(OPENSSL_FOUND) - SET(CURL_DEFINITIONS -DCURL_STATICLIB) -ENDIF(WITH_STATIC) - ADD_SUBDIRECTORY(common) IF(WITH_RYZOM_CLIENT) @@ -26,6 +17,30 @@ IF(WITH_RYZOM_CLIENT) ENDIF(WITH_LUA51) FIND_PACKAGE(Luabind REQUIRED) FIND_PACKAGE(CURL REQUIRED) + + IF(WIN32 OR CURL_LIBRARIES MATCHES "\\.a") + SET(CURL_STATIC ON) + ENDIF(WIN32 OR CURL_LIBRARIES MATCHES "\\.a") + + IF(CURL_STATIC) + SET(CURL_DEFINITIONS -DCURL_STATICLIB) + + FIND_PACKAGE(OpenSSL QUIET) + + IF(OPENSSL_FOUND) + SET(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) + SET(CURL_LIBRARIES ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES}) + ENDIF(OPENSSL_FOUND) + + # CURL Macports version depends on libidn and libintl too + IF(APPLE) + FIND_LIBRARY(IDN_LIBRARY idn) + FIND_LIBRARY(INTL_LIBRARY intl) + + SET(CURL_LIBRARIES ${CURL_LIBRARIES} ${IDN_LIBRARY} ${INTL_LIBRARY}) + ENDIF(APPLE) + ENDIF(CURL_STATIC) + FIND_PACKAGE(Libwww REQUIRED) ADD_SUBDIRECTORY(client) From 2b82f9a31c3c3012997500bff2b456a0c85ad7b9 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 7 May 2012 10:27:54 +0200 Subject: [PATCH 22/66] Changed: Use only static libraries under Mac OS X if WITH_STATIC_EXTERNAL is used Changed: Strip binaries under Mac OS X by default in Release (use WITH_SYMBOLS if you don't want) --- code/CMakeModules/nel.cmake | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index e6bf57101..331764d70 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -355,7 +355,7 @@ MACRO(NL_SETUP_BUILD) ENDIF(CMAKE_BUILD_TYPE MATCHES "Release") ENDIF(CMAKE_BUILD_TYPE MATCHES "Debug") - SET(HOST_CPU ${CMAKE_SYSTEM_PROCESSOR}) + SET(HOST_CPU ${CMAKE_HOST_SYSTEM_PROCESSOR}) IF(HOST_CPU MATCHES "amd64") SET(HOST_CPU "x86_64") @@ -382,6 +382,11 @@ MACRO(NL_SETUP_BUILD) # DEB_HOST_ARCH_ENDIAN is 'little' or 'big' # DEB_HOST_ARCH_BITS is '32' or '64' + IF(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + SET(CLANG ON) + MESSAGE(STATUS "Using Clang compiler") + ENDIF(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + # If target and host CPU are the same IF("${HOST_CPU}" STREQUAL "${TARGET_CPU}") # x86-compatible CPU @@ -397,8 +402,13 @@ MACRO(NL_SETUP_BUILD) ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8) SET(TARGET_CPU "x86") ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) + ELSEIF(HOST_CPU MATCHES "arm") + SET(TARGET_CPU "arm") + ELSE(HOST_CPU MATCHES "x86") + SET(TARGET_CPU "unknown") + MESSAGE(STATUS "Unknown architecture: ${HOST_CPU}") ENDIF(HOST_CPU MATCHES "x86") - # TODO: add checks for ARM and PPC + # TODO: add checks for PPC ELSE("${HOST_CPU}" STREQUAL "${TARGET_CPU}") MESSAGE(STATUS "Compiling on ${HOST_CPU} for ${TARGET_CPU}") ENDIF("${HOST_CPU}" STREQUAL "${TARGET_CPU}") @@ -409,6 +419,9 @@ MACRO(NL_SETUP_BUILD) ELSEIF(TARGET_CPU STREQUAL "x86") SET(TARGET_X86 1) SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DHAVE_X86") + ELSEIF(TARGET_CPU STREQUAL "arm") + SET(TARGET_ARM 1) + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DHAVE_ARM") ENDIF(TARGET_CPU STREQUAL "x86_64") # Fix library paths suffixes for Debian MultiArch @@ -514,12 +527,14 @@ MACRO(NL_SETUP_BUILD) IF(WITH_SYMBOLS) SET(NL_RELEASE_CFLAGS "${NL_RELEASE_CFLAGS} -g") ELSE(WITH_SYMBOLS) - IF(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + IF(APPLE) + SET(NL_RELEASE_LINKFLAGS "-Wl,-dead_strip -Wl,-x ${NL_RELEASE_LINKFLAGS}") + ELSE(APPLE) SET(NL_RELEASE_LINKFLAGS "-Wl,-s ${NL_RELEASE_LINKFLAGS}") - ENDIF(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + ENDIF(APPLE) ENDIF(WITH_SYMBOLS) - SET(NL_DEBUG_CFLAGS "-DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}") + SET(NL_DEBUG_CFLAGS "-g -DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}") SET(NL_RELEASE_CFLAGS "-DNL_RELEASE -DNDEBUG -O3 ${NL_RELEASE_CFLAGS}") ENDIF(MSVC) ENDMACRO(NL_SETUP_BUILD) @@ -710,7 +725,7 @@ MACRO(SETUP_EXTERNAL) ELSE(WIN32) IF(APPLE) IF(WITH_STATIC_EXTERNAL) - SET(CMAKE_FIND_LIBRARY_SUFFIXES .a .dylib .so) + SET(CMAKE_FIND_LIBRARY_SUFFIXES .a) ELSE(WITH_STATIC_EXTERNAL) SET(CMAKE_FIND_LIBRARY_SUFFIXES .dylib .so .a) ENDIF(WITH_STATIC_EXTERNAL) From 3f961a074919b49b0b95653791c50f65e4b565ac Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 7 May 2012 10:30:24 +0200 Subject: [PATCH 23/66] Changed: Set CMAKE_OSX_DEPLOYMENT_TARGET if not defined Changed: Use custom Info.plist Added: RYZOM_DATA_DIR option to copy data from there --- code/ryzom/client/src/CMakeLists.txt | 35 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/code/ryzom/client/src/CMakeLists.txt b/code/ryzom/client/src/CMakeLists.txt index 3971fb98f..26c8eb12a 100644 --- a/code/ryzom/client/src/CMakeLists.txt +++ b/code/ryzom/client/src/CMakeLists.txt @@ -42,30 +42,39 @@ SOURCE_GROUP("r2" FILES ${SRC_R2}) # on Mac, create a .App Bundle if(APPLE) + IF(NOT CMAKE_OSX_DEPLOYMENT_TARGET) + SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.6") + ENDIF(NOT CMAKE_OSX_DEPLOYMENT_TARGET) + SET(MACOSX_BUNDLE_INFO_STRING "Ryzom Core Client") - SET(MACOSX_BUNDLE_ICON_FILE "atys.icns") + SET(MACOSX_BUNDLE_ICON_FILE "ryzom.icns") SET(MACOSX_BUNDLE_GUI_IDENTIFIER "") SET(MACOSX_BUNDLE_LONG_VERSION_STRING ${NL_VERSION}) SET(MACOSX_BUNDLE_BUNDLE_NAME "Ryzom Core Client") SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "0.8") SET(MACOSX_BUNDLE_BUNDLE_VERSION "1.0") SET(MACOSX_BUNDLE_COPYRIGHT "Winchgate and The Ryzom Core Community") - - # TODO: in release mode, cmake could copy all the dylibs into the .app - # bundle for redistribution... should some part of cpack handle that? - # ADD_CUSTOM_COMMAND(TARGET ryzom_client POST_BUILD - # # make frameworks directory in app bundle - # COMMAND ${CMAKE_COMMAND} -E make_directory - # ${CMAKE_CURRENT_BINARY_DIR}/ryzom_client.app/Contents/Frameworks - # # copy framework into app bundle - # COMMAND ${CMAKE_COMMAND} -E copy ${SOME_LIBRARY} - # ${CMAKE_CURRENT_BINARY_DIR}/ryzom_client.app/Contents/Frameworks - # # ... - # # install_name_tool the lib pathes + SET(RYZOM_OUTPUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${MACOSX_BUNDLE_BUNDLE_NAME}.app) + SET(RYZOM_CONTENTS_DIR ${RYZOM_OUTPUT_DIR}/Contents) + SET(RYZOM_RESOURCES_DIR ${RYZOM_CONTENTS_DIR}/Resources) + SET(MAC_RESOURCES_DIR ${CMAKE_SOURCE_DIR}/ryzom/client/macosx) ENDIF(APPLE) ADD_EXECUTABLE(ryzom_client WIN32 MACOSX_BUNDLE ${SRC} ${SRC_INTERFACE} ${SRC_MODE} ${SRC_R2}) +IF(APPLE) + SET_TARGET_PROPERTIES(ryzom_client PROPERTIES OUTPUT_NAME ${MACOSX_BUNDLE_BUNDLE_NAME}) + SET_TARGET_PROPERTIES(ryzom_client PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${MAC_RESOURCES_DIR}/Info.plist) + ADD_CUSTOM_COMMAND(TARGET ryzom_client PRE_BUILD COMMAND mkdir -p ${RYZOM_RESOURCES_DIR}) + ADD_CUSTOM_COMMAND(TARGET ryzom_client POST_BUILD COMMAND cp ARGS ${MAC_RESOURCES_DIR}/PkgInfo ${RYZOM_CONTENTS_DIR}) + ADD_CUSTOM_COMMAND(TARGET ryzom_client POST_BUILD COMMAND cp ARGS ${MAC_RESOURCES_DIR}/ryzom.icns ${RYZOM_RESOURCES_DIR}) + ADD_CUSTOM_COMMAND(TARGET ryzom_client POST_BUILD COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/ryzom/client/client_default.cfg ${RYZOM_RESOURCES_DIR}) + + IF(RYZOM_DATA_DIR) + ADD_CUSTOM_COMMAND(TARGET ryzom_client POST_BUILD COMMAND cp -R ARGS ${RYZOM_DATA_DIR} ${RYZOM_RESOURCES_DIR}) + ENDIF(RYZOM_DATA_DIR) +ENDIF(APPLE) + INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBXML2_INCLUDE_DIR} From 38ae47456c1fd116a84369613c05bfd99034dde8 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 7 May 2012 10:30:37 +0200 Subject: [PATCH 24/66] Added: Mac OS X resources --- code/ryzom/client/macosx/Info.plist | 40 ++++++++++++++++++++++++++++ code/ryzom/client/macosx/PkgInfo | 1 + code/ryzom/client/macosx/ryzom.icns | Bin 0 -> 642841 bytes 3 files changed, 41 insertions(+) create mode 100644 code/ryzom/client/macosx/Info.plist create mode 100644 code/ryzom/client/macosx/PkgInfo create mode 100644 code/ryzom/client/macosx/ryzom.icns diff --git a/code/ryzom/client/macosx/Info.plist b/code/ryzom/client/macosx/Info.plist new file mode 100644 index 000000000..8072a90c1 --- /dev/null +++ b/code/ryzom/client/macosx/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + LSMinimumSystemVersion + ${CMAKE_OSX_DEPLOYMENT_TARGET}.0 + LSFileQuarantineEnabled + + CSResourcesFileMapped + + LSRequiresCarbon + + LSApplicationCategoryType + public.app-category.role-playing-games + + diff --git a/code/ryzom/client/macosx/PkgInfo b/code/ryzom/client/macosx/PkgInfo new file mode 100644 index 000000000..bd04210fb --- /dev/null +++ b/code/ryzom/client/macosx/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/code/ryzom/client/macosx/ryzom.icns b/code/ryzom/client/macosx/ryzom.icns new file mode 100644 index 0000000000000000000000000000000000000000..6fb077d967e3fa0909260c7865d04e0b1fbdb383 GIT binary patch literal 642841 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